~ubuntu-branches/ubuntu/trusty/libv8/trusty

« back to all changes in this revision

Viewing changes to src/heap.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jérémy Lal
  • Date: 2010-06-17 00:06:53 UTC
  • mfrom: (1.2.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20100617000653-9tg3xdjru39y3nhm
Tags: 2.2.18-1
* New upstream release, followed the procedure of README.source to update. 
* Drops 0005-constraints-visibility.patch (applied upstream).

Show diffs side-by-side

added added

removed removed

Lines of Context:
115
115
Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
116
116
 
117
117
int Heap::mc_count_ = 0;
 
118
int Heap::ms_count_ = 0;
118
119
int Heap::gc_count_ = 0;
119
120
 
 
121
GCTracer* Heap::tracer_ = NULL;
 
122
 
120
123
int Heap::unflattened_strings_length_ = 0;
121
124
 
122
125
int Heap::always_allocate_scope_depth_ = 0;
130
133
bool Heap::disallow_allocation_failure_ = false;
131
134
#endif  // DEBUG
132
135
 
 
136
int GCTracer::alive_after_last_gc_ = 0;
 
137
double GCTracer::last_gc_end_timestamp_ = 0.0;
 
138
int GCTracer::max_gc_pause_ = 0;
 
139
int GCTracer::max_alive_after_gc_ = 0;
 
140
int GCTracer::min_in_mutator_ = kMaxInt;
133
141
 
134
142
int Heap::Capacity() {
135
143
  if (!HasBeenSetup()) return 0;
306
314
 
307
315
void Heap::GarbageCollectionPrologue() {
308
316
  TranscendentalCache::Clear();
 
317
  ClearJSFunctionResultCaches();
309
318
  gc_count_++;
310
319
  unflattened_strings_length_ = 0;
311
320
#ifdef DEBUG
317
326
  }
318
327
 
319
328
  if (FLAG_gc_verbose) Print();
320
 
 
321
 
  if (FLAG_print_rset) {
322
 
    // Not all spaces have remembered set bits that we care about.
323
 
    old_pointer_space_->PrintRSet();
324
 
    map_space_->PrintRSet();
325
 
    lo_space_->PrintRSet();
326
 
  }
327
329
#endif
328
330
 
329
331
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
510
512
      Heap::CollectGarbage(cell_space_size, CELL_SPACE);
511
513
      gc_performed = true;
512
514
    }
513
 
    // We add a slack-factor of 2 in order to have space for the remembered
514
 
    // set and a series of large-object allocations that are only just larger
515
 
    // than the page size.
 
515
    // We add a slack-factor of 2 in order to have space for a series of
 
516
    // large-object allocations that are only just larger than the page size.
516
517
    large_object_size *= 2;
517
518
    // The ReserveSpace method on the large object space checks how much
518
519
    // we can expand the old generation.  This includes expansion caused by
541
542
}
542
543
 
543
544
 
 
545
class ClearThreadJSFunctionResultCachesVisitor: public ThreadVisitor  {
 
546
  virtual void VisitThread(ThreadLocalTop* top) {
 
547
    Context* context = top->context_;
 
548
    if (context == NULL) return;
 
549
 
 
550
    FixedArray* caches =
 
551
      context->global()->global_context()->jsfunction_result_caches();
 
552
    int length = caches->length();
 
553
    for (int i = 0; i < length; i++) {
 
554
      JSFunctionResultCache::cast(caches->get(i))->Clear();
 
555
    }
 
556
  }
 
557
};
 
558
 
 
559
 
 
560
void Heap::ClearJSFunctionResultCaches() {
 
561
  if (Bootstrapper::IsActive()) return;
 
562
  ClearThreadJSFunctionResultCachesVisitor visitor;
 
563
  ThreadManager::IterateArchivedThreads(&visitor);
 
564
}
 
565
 
 
566
 
 
567
#ifdef DEBUG
 
568
 
 
569
enum PageWatermarkValidity {
 
570
  ALL_VALID,
 
571
  ALL_INVALID
 
572
};
 
573
 
 
574
static void VerifyPageWatermarkValidity(PagedSpace* space,
 
575
                                        PageWatermarkValidity validity) {
 
576
  PageIterator it(space, PageIterator::PAGES_IN_USE);
 
577
  bool expected_value = (validity == ALL_VALID);
 
578
  while (it.has_next()) {
 
579
    Page* page = it.next();
 
580
    ASSERT(page->IsWatermarkValid() == expected_value);
 
581
  }
 
582
}
 
583
#endif
 
584
 
 
585
 
544
586
void Heap::PerformGarbageCollection(AllocationSpace space,
545
587
                                    GarbageCollector collector,
546
588
                                    GCTracer* tracer) {
547
589
  VerifySymbolTable();
548
590
  if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
549
591
    ASSERT(!allocation_allowed_);
550
 
    GCTracer::ExternalScope scope(tracer);
 
592
    GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
551
593
    global_gc_prologue_callback_();
552
594
  }
553
595
 
563
605
  EnsureFromSpaceIsCommitted();
564
606
 
565
607
  if (collector == MARK_COMPACTOR) {
 
608
    if (FLAG_flush_code) {
 
609
      // Flush all potentially unused code.
 
610
      FlushCode();
 
611
    }
 
612
 
566
613
    // Perform mark-sweep with optional compaction.
567
614
    MarkCompact(tracer);
568
615
 
573
620
        old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2);
574
621
    old_gen_exhausted_ = false;
575
622
  } else {
 
623
    tracer_ = tracer;
576
624
    Scavenge();
 
625
    tracer_ = NULL;
577
626
  }
578
627
 
579
628
  Counters::objs_since_last_young.Set(0);
580
629
 
581
630
  if (collector == MARK_COMPACTOR) {
582
631
    DisableAssertNoAllocation allow_allocation;
583
 
    GCTracer::ExternalScope scope(tracer);
 
632
    GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
584
633
    GlobalHandles::PostGarbageCollectionProcessing();
585
634
  }
586
635
 
604
653
 
605
654
  if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
606
655
    ASSERT(!allocation_allowed_);
607
 
    GCTracer::ExternalScope scope(tracer);
 
656
    GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
608
657
    global_gc_epilogue_callback_();
609
658
  }
610
659
  VerifySymbolTable();
613
662
 
614
663
void Heap::MarkCompact(GCTracer* tracer) {
615
664
  gc_state_ = MARK_COMPACT;
616
 
  mc_count_++;
617
 
  tracer->set_full_gc_count(mc_count_);
618
665
  LOG(ResourceEvent("markcompact", "begin"));
619
666
 
620
667
  MarkCompactCollector::Prepare(tracer);
621
668
 
622
669
  bool is_compacting = MarkCompactCollector::IsCompacting();
623
670
 
 
671
  if (is_compacting) {
 
672
    mc_count_++;
 
673
  } else {
 
674
    ms_count_++;
 
675
  }
 
676
  tracer->set_full_gc_count(mc_count_ + ms_count_);
 
677
 
624
678
  MarkCompactPrologue(is_compacting);
625
679
 
626
680
  MarkCompactCollector::CollectGarbage();
651
705
  Top::MarkCompactPrologue(is_compacting);
652
706
  ThreadManager::MarkCompactPrologue(is_compacting);
653
707
 
 
708
  CompletelyClearInstanceofCache();
 
709
 
654
710
  if (is_compacting) FlushNumberStringCache();
655
711
}
656
712
 
777
833
 
778
834
  gc_state_ = SCAVENGE;
779
835
 
 
836
  Page::FlipMeaningOfInvalidatedWatermarkFlag();
 
837
#ifdef DEBUG
 
838
  VerifyPageWatermarkValidity(old_pointer_space_, ALL_VALID);
 
839
  VerifyPageWatermarkValidity(map_space_, ALL_VALID);
 
840
#endif
 
841
 
 
842
  // We do not update an allocation watermark of the top page during linear
 
843
  // allocation to avoid overhead. So to maintain the watermark invariant
 
844
  // we have to manually cache the watermark and mark the top page as having an
 
845
  // invalid watermark. This guarantees that dirty regions iteration will use a
 
846
  // correct watermark even if a linear allocation happens.
 
847
  old_pointer_space_->FlushTopPageWatermark();
 
848
  map_space_->FlushTopPageWatermark();
 
849
 
780
850
  // Implements Cheney's copying algorithm
781
851
  LOG(ResourceEvent("scavenge", "begin"));
782
852
 
819
889
 
820
890
  // Copy objects reachable from the old generation.  By definition,
821
891
  // there are no intergenerational pointers in code or data spaces.
822
 
  IterateRSet(old_pointer_space_, &ScavengePointer);
823
 
  IterateRSet(map_space_, &ScavengePointer);
824
 
  lo_space_->IterateRSet(&ScavengePointer);
 
892
  IterateDirtyRegions(old_pointer_space_,
 
893
                      &IteratePointersInDirtyRegion,
 
894
                      &ScavengePointer,
 
895
                      WATERMARK_CAN_BE_INVALID);
 
896
 
 
897
  IterateDirtyRegions(map_space_,
 
898
                      &IteratePointersInDirtyMapsRegion,
 
899
                      &ScavengePointer,
 
900
                      WATERMARK_CAN_BE_INVALID);
 
901
 
 
902
  lo_space_->IterateDirtyRegions(&ScavengePointer);
825
903
 
826
904
  // Copy objects reachable from cells by scavenging cell values directly.
827
905
  HeapObjectIterator cell_iterator(cell_space_);
924
1002
      // Copy the from-space object to its new location (given by the
925
1003
      // forwarding address) and fix its map.
926
1004
      HeapObject* target = source->map_word().ToForwardingAddress();
927
 
      CopyBlock(reinterpret_cast<Object**>(target->address()),
928
 
                reinterpret_cast<Object**>(source->address()),
929
 
                source->SizeFromMap(map));
 
1005
      int size = source->SizeFromMap(map);
 
1006
      CopyBlock(target->address(), source->address(), size);
930
1007
      target->set_map(map);
931
1008
 
932
1009
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
934
1011
      RecordCopiedObject(target);
935
1012
#endif
936
1013
      // Visit the newly copied object for pointers to new space.
937
 
      target->Iterate(scavenge_visitor);
938
 
      UpdateRSet(target);
 
1014
      ASSERT(!target->IsMap());
 
1015
      IterateAndMarkPointersToNewSpace(target->address(),
 
1016
                                       target->address() + size,
 
1017
                                       &ScavengePointer);
939
1018
    }
940
1019
 
941
1020
    // Take another spin if there are now unswept objects in new space
946
1025
}
947
1026
 
948
1027
 
949
 
void Heap::ClearRSetRange(Address start, int size_in_bytes) {
950
 
  uint32_t start_bit;
951
 
  Address start_word_address =
952
 
      Page::ComputeRSetBitPosition(start, 0, &start_bit);
953
 
  uint32_t end_bit;
954
 
  Address end_word_address =
955
 
      Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize,
956
 
                                   0,
957
 
                                   &end_bit);
958
 
 
959
 
  // We want to clear the bits in the starting word starting with the
960
 
  // first bit, and in the ending word up to and including the last
961
 
  // bit.  Build a pair of bitmasks to do that.
962
 
  uint32_t start_bitmask = start_bit - 1;
963
 
  uint32_t end_bitmask = ~((end_bit << 1) - 1);
964
 
 
965
 
  // If the start address and end address are the same, we mask that
966
 
  // word once, otherwise mask the starting and ending word
967
 
  // separately and all the ones in between.
968
 
  if (start_word_address == end_word_address) {
969
 
    Memory::uint32_at(start_word_address) &= (start_bitmask | end_bitmask);
970
 
  } else {
971
 
    Memory::uint32_at(start_word_address) &= start_bitmask;
972
 
    Memory::uint32_at(end_word_address) &= end_bitmask;
973
 
    start_word_address += kIntSize;
974
 
    memset(start_word_address, 0, end_word_address - start_word_address);
975
 
  }
976
 
}
977
 
 
978
 
 
979
 
class UpdateRSetVisitor: public ObjectVisitor {
980
 
 public:
981
 
 
982
 
  void VisitPointer(Object** p) {
983
 
    UpdateRSet(p);
984
 
  }
985
 
 
986
 
  void VisitPointers(Object** start, Object** end) {
987
 
    // Update a store into slots [start, end), used (a) to update remembered
988
 
    // set when promoting a young object to old space or (b) to rebuild
989
 
    // remembered sets after a mark-compact collection.
990
 
    for (Object** p = start; p < end; p++) UpdateRSet(p);
991
 
  }
992
 
 private:
993
 
 
994
 
  void UpdateRSet(Object** p) {
995
 
    // The remembered set should not be set.  It should be clear for objects
996
 
    // newly copied to old space, and it is cleared before rebuilding in the
997
 
    // mark-compact collector.
998
 
    ASSERT(!Page::IsRSetSet(reinterpret_cast<Address>(p), 0));
999
 
    if (Heap::InNewSpace(*p)) {
1000
 
      Page::SetRSet(reinterpret_cast<Address>(p), 0);
1001
 
    }
1002
 
  }
1003
 
};
1004
 
 
1005
 
 
1006
 
int Heap::UpdateRSet(HeapObject* obj) {
1007
 
  ASSERT(!InNewSpace(obj));
1008
 
  // Special handling of fixed arrays to iterate the body based on the start
1009
 
  // address and offset.  Just iterating the pointers as in UpdateRSetVisitor
1010
 
  // will not work because Page::SetRSet needs to have the start of the
1011
 
  // object for large object pages.
1012
 
  if (obj->IsFixedArray()) {
1013
 
    FixedArray* array = FixedArray::cast(obj);
1014
 
    int length = array->length();
1015
 
    for (int i = 0; i < length; i++) {
1016
 
      int offset = FixedArray::kHeaderSize + i * kPointerSize;
1017
 
      ASSERT(!Page::IsRSetSet(obj->address(), offset));
1018
 
      if (Heap::InNewSpace(array->get(i))) {
1019
 
        Page::SetRSet(obj->address(), offset);
1020
 
      }
1021
 
    }
1022
 
  } else if (!obj->IsCode()) {
1023
 
    // Skip code object, we know it does not contain inter-generational
1024
 
    // pointers.
1025
 
    UpdateRSetVisitor v;
1026
 
    obj->Iterate(&v);
1027
 
  }
1028
 
  return obj->Size();
1029
 
}
1030
 
 
1031
 
 
1032
 
void Heap::RebuildRSets() {
1033
 
  // By definition, we do not care about remembered set bits in code,
1034
 
  // data, or cell spaces.
1035
 
  map_space_->ClearRSet();
1036
 
  RebuildRSets(map_space_);
1037
 
 
1038
 
  old_pointer_space_->ClearRSet();
1039
 
  RebuildRSets(old_pointer_space_);
1040
 
 
1041
 
  Heap::lo_space_->ClearRSet();
1042
 
  RebuildRSets(lo_space_);
1043
 
}
1044
 
 
1045
 
 
1046
 
void Heap::RebuildRSets(PagedSpace* space) {
1047
 
  HeapObjectIterator it(space);
1048
 
  for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1049
 
    Heap::UpdateRSet(obj);
1050
 
}
1051
 
 
1052
 
 
1053
 
void Heap::RebuildRSets(LargeObjectSpace* space) {
1054
 
  LargeObjectIterator it(space);
1055
 
  for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1056
 
    Heap::UpdateRSet(obj);
1057
 
}
1058
 
 
1059
 
 
1060
1028
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
1061
1029
void Heap::RecordCopiedObject(HeapObject* obj) {
1062
1030
  bool should_record = false;
1082
1050
                                HeapObject* target,
1083
1051
                                int size) {
1084
1052
  // Copy the content of source to target.
1085
 
  CopyBlock(reinterpret_cast<Object**>(target->address()),
1086
 
            reinterpret_cast<Object**>(source->address()),
1087
 
            size);
 
1053
  CopyBlock(target->address(), source->address(), size);
1088
1054
 
1089
1055
  // Set the forwarding address.
1090
1056
  source->set_map_word(MapWord::FromForwardingAddress(target));
1139
1105
    if (object_size > MaxObjectSizeInPagedSpace()) {
1140
1106
      result = lo_space_->AllocateRawFixedArray(object_size);
1141
1107
      if (!result->IsFailure()) {
1142
 
        // Save the from-space object pointer and its map pointer at the
1143
 
        // top of the to space to be swept and copied later.  Write the
1144
 
        // forwarding address over the map word of the from-space
1145
 
        // object.
1146
1108
        HeapObject* target = HeapObject::cast(result);
1147
 
        promotion_queue.insert(object, first_word.ToMap());
1148
 
        object->set_map_word(MapWord::FromForwardingAddress(target));
1149
 
 
1150
 
        // Give the space allocated for the result a proper map by
1151
 
        // treating it as a free list node (not linked into the free
1152
 
        // list).
1153
 
        FreeListNode* node = FreeListNode::FromAddress(target->address());
1154
 
        node->set_size(object_size);
1155
 
 
1156
 
        *p = target;
 
1109
 
 
1110
        if (object->IsFixedArray()) {
 
1111
          // Save the from-space object pointer and its map pointer at the
 
1112
          // top of the to space to be swept and copied later.  Write the
 
1113
          // forwarding address over the map word of the from-space
 
1114
          // object.
 
1115
          promotion_queue.insert(object, first_word.ToMap());
 
1116
          object->set_map_word(MapWord::FromForwardingAddress(target));
 
1117
 
 
1118
          // Give the space allocated for the result a proper map by
 
1119
          // treating it as a free list node (not linked into the free
 
1120
          // list).
 
1121
          FreeListNode* node = FreeListNode::FromAddress(target->address());
 
1122
          node->set_size(object_size);
 
1123
 
 
1124
          *p = target;
 
1125
        } else {
 
1126
          // In large object space only fixed arrays might possibly contain
 
1127
          // intergenerational references.
 
1128
          // All other objects can be copied immediately and not revisited.
 
1129
          *p = MigrateObject(object, target, object_size);
 
1130
        }
 
1131
 
 
1132
        tracer()->increment_promoted_objects_size(object_size);
1157
1133
        return;
1158
1134
      }
1159
1135
    } else {
1189
1165
          (*p)->Iterate(&v);
1190
1166
#endif
1191
1167
        }
 
1168
        tracer()->increment_promoted_objects_size(object_size);
1192
1169
        return;
1193
1170
      }
1194
1171
    }
1641
1618
  // loop above because it needs to be allocated manually with the special
1642
1619
  // hash code in place. The hash code for the hidden_symbol is zero to ensure
1643
1620
  // that it will always be at the first entry in property descriptors.
1644
 
  obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask);
 
1621
  obj = AllocateSymbol(CStrVector(""), 0, String::kZeroHash);
1645
1622
  if (obj->IsFailure()) return false;
1646
1623
  hidden_symbol_ = String::cast(obj);
1647
1624
 
1662
1639
  if (obj->IsFailure()) return false;
1663
1640
  set_non_monomorphic_cache(NumberDictionary::cast(obj));
1664
1641
 
 
1642
  set_instanceof_cache_function(Smi::FromInt(0));
 
1643
  set_instanceof_cache_map(Smi::FromInt(0));
 
1644
  set_instanceof_cache_answer(Smi::FromInt(0));
 
1645
 
1665
1646
  CreateFixedStubs();
1666
1647
 
1667
1648
  if (InitializeNumberStringCache()->IsFailure()) return false;
1873
1854
  share->set_compiler_hints(0);
1874
1855
  share->set_this_property_assignments_count(0);
1875
1856
  share->set_this_property_assignments(undefined_value());
 
1857
  share->set_num_literals(0);
 
1858
  share->set_end_position(0);
 
1859
  share->set_function_token_position(0);
1876
1860
  return result;
1877
1861
}
1878
1862
 
2035
2019
  }
2036
2020
 
2037
2021
  // Make an attempt to flatten the buffer to reduce access time.
2038
 
  buffer->TryFlatten();
 
2022
  buffer = buffer->TryFlattenGetString();
2039
2023
 
2040
2024
  Object* result = buffer->IsAsciiRepresentation()
2041
2025
      ? AllocateRawAsciiString(length, pretenure )
2134
2118
      : lo_space_->AllocateRaw(size);
2135
2119
  if (result->IsFailure()) return result;
2136
2120
 
2137
 
  reinterpret_cast<Array*>(result)->set_map(byte_array_map());
2138
 
  reinterpret_cast<Array*>(result)->set_length(length);
 
2121
  reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map());
 
2122
  reinterpret_cast<ByteArray*>(result)->set_length(length);
2139
2123
  return result;
2140
2124
}
2141
2125
 
2150
2134
  Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
2151
2135
  if (result->IsFailure()) return result;
2152
2136
 
2153
 
  reinterpret_cast<Array*>(result)->set_map(byte_array_map());
2154
 
  reinterpret_cast<Array*>(result)->set_length(length);
 
2137
  reinterpret_cast<ByteArray*>(result)->set_map(byte_array_map());
 
2138
  reinterpret_cast<ByteArray*>(result)->set_length(length);
2155
2139
  return result;
2156
2140
}
2157
2141
 
2205
2189
}
2206
2190
 
2207
2191
 
 
2192
// The StackVisitor is used to traverse all the archived threads to see if
 
2193
// there are activations on any of the stacks corresponding to the code.
 
2194
class FlushingStackVisitor : public ThreadVisitor {
 
2195
 public:
 
2196
  explicit FlushingStackVisitor(Code* code) : found_(false), code_(code) {}
 
2197
 
 
2198
  void VisitThread(ThreadLocalTop* top) {
 
2199
    // If we already found the code in a previous traversed thread we return.
 
2200
    if (found_) return;
 
2201
 
 
2202
    for (StackFrameIterator it(top); !it.done(); it.Advance()) {
 
2203
      if (code_->contains(it.frame()->pc())) {
 
2204
        found_ = true;
 
2205
        return;
 
2206
      }
 
2207
    }
 
2208
  }
 
2209
  bool FoundCode() {return found_;}
 
2210
 
 
2211
 private:
 
2212
  bool found_;
 
2213
  Code* code_;
 
2214
};
 
2215
 
 
2216
 
 
2217
static void FlushCodeForFunction(SharedFunctionInfo* function_info) {
 
2218
  // The function must be compiled and have the source code available,
 
2219
  // to be able to recompile it in case we need the function again.
 
2220
  if (!(function_info->is_compiled() && function_info->HasSourceCode())) return;
 
2221
 
 
2222
  // We never flush code for Api functions.
 
2223
  if (function_info->IsApiFunction()) return;
 
2224
 
 
2225
  // Only flush code for functions.
 
2226
  if (!function_info->code()->kind() == Code::FUNCTION) return;
 
2227
 
 
2228
  // Function must be lazy compilable.
 
2229
  if (!function_info->allows_lazy_compilation()) return;
 
2230
 
 
2231
  // If this is a full script wrapped in a function we do no flush the code.
 
2232
  if (function_info->is_toplevel()) return;
 
2233
 
 
2234
  // If this function is in the compilation cache we do not flush the code.
 
2235
  if (CompilationCache::HasFunction(function_info)) return;
 
2236
 
 
2237
  // Make sure we are not referencing the code from the stack.
 
2238
  for (StackFrameIterator it; !it.done(); it.Advance()) {
 
2239
    if (function_info->code()->contains(it.frame()->pc())) return;
 
2240
  }
 
2241
  // Iterate the archived stacks in all threads to check if
 
2242
  // the code is referenced.
 
2243
  FlushingStackVisitor threadvisitor(function_info->code());
 
2244
  ThreadManager::IterateArchivedThreads(&threadvisitor);
 
2245
  if (threadvisitor.FoundCode()) return;
 
2246
 
 
2247
  HandleScope scope;
 
2248
  // Compute the lazy compilable version of the code.
 
2249
  function_info->set_code(*ComputeLazyCompile(function_info->length()));
 
2250
}
 
2251
 
 
2252
 
 
2253
void Heap::FlushCode() {
 
2254
#ifdef ENABLE_DEBUGGER_SUPPORT
 
2255
  // Do not flush code if the debugger is loaded or there are breakpoints.
 
2256
  if (Debug::IsLoaded() || Debug::has_break_points()) return;
 
2257
#endif
 
2258
  HeapObjectIterator it(old_pointer_space());
 
2259
  for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
 
2260
    if (obj->IsJSFunction()) {
 
2261
      JSFunction* jsfunction = JSFunction::cast(obj);
 
2262
 
 
2263
      // The function must have a valid context and not be a builtin.
 
2264
      if (jsfunction->unchecked_context()->IsContext() &&
 
2265
          !jsfunction->IsBuiltin()) {
 
2266
        FlushCodeForFunction(jsfunction->shared());
 
2267
      }
 
2268
    }
 
2269
  }
 
2270
}
 
2271
 
 
2272
 
2208
2273
Object* Heap::CreateCode(const CodeDesc& desc,
2209
2274
                         ZoneScopeInfo* sinfo,
2210
2275
                         Code::Flags flags,
2267
2332
  // Copy code object.
2268
2333
  Address old_addr = code->address();
2269
2334
  Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
2270
 
  CopyBlock(reinterpret_cast<Object**>(new_addr),
2271
 
            reinterpret_cast<Object**>(old_addr),
2272
 
            obj_size);
 
2335
  CopyBlock(new_addr, old_addr, obj_size);
2273
2336
  // Relocate the copy.
2274
2337
  Code* new_code = Code::cast(result);
2275
2338
  ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
2415
2478
  // Copy the content. The arguments boilerplate doesn't have any
2416
2479
  // fields that point to new space so it's safe to skip the write
2417
2480
  // barrier here.
2418
 
  CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()),
2419
 
            reinterpret_cast<Object**>(boilerplate->address()),
 
2481
  CopyBlock(HeapObject::cast(result)->address(),
 
2482
            boilerplate->address(),
2420
2483
            kArgumentsObjectSize);
2421
2484
 
2422
2485
  // Set the two properties.
2638
2701
    clone = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
2639
2702
    if (clone->IsFailure()) return clone;
2640
2703
    Address clone_address = HeapObject::cast(clone)->address();
2641
 
    CopyBlock(reinterpret_cast<Object**>(clone_address),
2642
 
              reinterpret_cast<Object**>(source->address()),
 
2704
    CopyBlock(clone_address,
 
2705
              source->address(),
2643
2706
              object_size);
2644
2707
    // Update write barrier for all fields that lie beyond the header.
2645
2708
    RecordWrites(clone_address,
2651
2714
    ASSERT(Heap::InNewSpace(clone));
2652
2715
    // Since we know the clone is allocated in new space, we can copy
2653
2716
    // the contents without worrying about updating the write barrier.
2654
 
    CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()),
2655
 
              reinterpret_cast<Object**>(source->address()),
 
2717
    CopyBlock(HeapObject::cast(clone)->address(),
 
2718
              source->address(),
2656
2719
              object_size);
2657
2720
  }
2658
2721
 
2923
2986
  Object* result = AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
2924
2987
  if (result->IsFailure()) return result;
2925
2988
  // Initialize the object.
2926
 
  reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2927
 
  reinterpret_cast<Array*>(result)->set_length(0);
 
2989
  reinterpret_cast<FixedArray*>(result)->set_map(fixed_array_map());
 
2990
  reinterpret_cast<FixedArray*>(result)->set_length(0);
2928
2991
  return result;
2929
2992
}
2930
2993
 
2949
3012
  if (obj->IsFailure()) return obj;
2950
3013
  if (Heap::InNewSpace(obj)) {
2951
3014
    HeapObject* dst = HeapObject::cast(obj);
2952
 
    CopyBlock(reinterpret_cast<Object**>(dst->address()),
2953
 
              reinterpret_cast<Object**>(src->address()),
2954
 
              FixedArray::SizeFor(len));
 
3015
    CopyBlock(dst->address(), src->address(), FixedArray::SizeFor(len));
2955
3016
    return obj;
2956
3017
  }
2957
3018
  HeapObject::cast(obj)->set_map(src->map());
2972
3033
  Object* result = AllocateRawFixedArray(length);
2973
3034
  if (!result->IsFailure()) {
2974
3035
    // Initialize header.
2975
 
    reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2976
 
    FixedArray* array = FixedArray::cast(result);
 
3036
    FixedArray* array = reinterpret_cast<FixedArray*>(result);
 
3037
    array->set_map(fixed_array_map());
2977
3038
    array->set_length(length);
2978
3039
    // Initialize body.
2979
3040
    ASSERT(!Heap::InNewSpace(undefined_value()));
3000
3061
    space = LO_SPACE;
3001
3062
  }
3002
3063
 
3003
 
  // Specialize allocation for the space.
3004
 
  Object* result = Failure::OutOfMemoryException();
3005
 
  if (space == NEW_SPACE) {
3006
 
    // We cannot use Heap::AllocateRaw() because it will not properly
3007
 
    // allocate extra remembered set bits if always_allocate() is true and
3008
 
    // new space allocation fails.
3009
 
    result = new_space_.AllocateRaw(size);
3010
 
    if (result->IsFailure() && always_allocate()) {
3011
 
      if (size <= MaxObjectSizeInPagedSpace()) {
3012
 
        result = old_pointer_space_->AllocateRaw(size);
3013
 
      } else {
3014
 
        result = lo_space_->AllocateRawFixedArray(size);
3015
 
      }
3016
 
    }
3017
 
  } else if (space == OLD_POINTER_SPACE) {
3018
 
    result = old_pointer_space_->AllocateRaw(size);
3019
 
  } else {
3020
 
    ASSERT(space == LO_SPACE);
3021
 
    result = lo_space_->AllocateRawFixedArray(size);
3022
 
  }
3023
 
  return result;
 
3064
  AllocationSpace retry_space =
 
3065
      (size <= MaxObjectSizeInPagedSpace()) ? OLD_POINTER_SPACE : LO_SPACE;
 
3066
 
 
3067
  return AllocateRaw(size, space, retry_space);
3024
3068
}
3025
3069
 
3026
3070
 
3068
3112
Object* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
3069
3113
  Object* result = Heap::AllocateFixedArray(length, pretenure);
3070
3114
  if (result->IsFailure()) return result;
3071
 
  reinterpret_cast<Array*>(result)->set_map(hash_table_map());
 
3115
  reinterpret_cast<HeapObject*>(result)->set_map(hash_table_map());
3072
3116
  ASSERT(result->IsHashTable());
3073
3117
  return result;
3074
3118
}
3320
3364
 
3321
3365
 
3322
3366
#ifdef DEBUG
 
3367
static void DummyScavengePointer(HeapObject** p) {
 
3368
}
 
3369
 
 
3370
 
 
3371
static void VerifyPointersUnderWatermark(
 
3372
    PagedSpace* space,
 
3373
    DirtyRegionCallback visit_dirty_region) {
 
3374
  PageIterator it(space, PageIterator::PAGES_IN_USE);
 
3375
 
 
3376
  while (it.has_next()) {
 
3377
    Page* page = it.next();
 
3378
    Address start = page->ObjectAreaStart();
 
3379
    Address end = page->AllocationWatermark();
 
3380
 
 
3381
    Heap::IterateDirtyRegions(Page::kAllRegionsDirtyMarks,
 
3382
                              start,
 
3383
                              end,
 
3384
                              visit_dirty_region,
 
3385
                              &DummyScavengePointer);
 
3386
  }
 
3387
}
 
3388
 
 
3389
 
 
3390
static void VerifyPointersUnderWatermark(LargeObjectSpace* space) {
 
3391
  LargeObjectIterator it(space);
 
3392
  for (HeapObject* object = it.next(); object != NULL; object = it.next()) {
 
3393
    if (object->IsFixedArray()) {
 
3394
      Address slot_address = object->address();
 
3395
      Address end = object->address() + object->Size();
 
3396
 
 
3397
      while (slot_address < end) {
 
3398
        HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address);
 
3399
        // When we are not in GC the Heap::InNewSpace() predicate
 
3400
        // checks that pointers which satisfy predicate point into
 
3401
        // the active semispace.
 
3402
        Heap::InNewSpace(*slot);
 
3403
        slot_address += kPointerSize;
 
3404
      }
 
3405
    }
 
3406
  }
 
3407
}
 
3408
 
 
3409
 
3323
3410
void Heap::Verify() {
3324
3411
  ASSERT(HasBeenSetup());
3325
3412
 
3328
3415
 
3329
3416
  new_space_.Verify();
3330
3417
 
3331
 
  VerifyPointersAndRSetVisitor rset_visitor;
3332
 
  old_pointer_space_->Verify(&rset_visitor);
3333
 
  map_space_->Verify(&rset_visitor);
3334
 
 
3335
 
  VerifyPointersVisitor no_rset_visitor;
3336
 
  old_data_space_->Verify(&no_rset_visitor);
3337
 
  code_space_->Verify(&no_rset_visitor);
3338
 
  cell_space_->Verify(&no_rset_visitor);
 
3418
  VerifyPointersAndDirtyRegionsVisitor dirty_regions_visitor;
 
3419
  old_pointer_space_->Verify(&dirty_regions_visitor);
 
3420
  map_space_->Verify(&dirty_regions_visitor);
 
3421
 
 
3422
  VerifyPointersUnderWatermark(old_pointer_space_,
 
3423
                               &IteratePointersInDirtyRegion);
 
3424
  VerifyPointersUnderWatermark(map_space_,
 
3425
                               &IteratePointersInDirtyMapsRegion);
 
3426
  VerifyPointersUnderWatermark(lo_space_);
 
3427
 
 
3428
  VerifyPageWatermarkValidity(old_pointer_space_, ALL_INVALID);
 
3429
  VerifyPageWatermarkValidity(map_space_, ALL_INVALID);
 
3430
 
 
3431
  VerifyPointersVisitor no_dirty_regions_visitor;
 
3432
  old_data_space_->Verify(&no_dirty_regions_visitor);
 
3433
  code_space_->Verify(&no_dirty_regions_visitor);
 
3434
  cell_space_->Verify(&no_dirty_regions_visitor);
3339
3435
 
3340
3436
  lo_space_->Verify();
3341
3437
}
3388
3484
#endif  // DEBUG
3389
3485
 
3390
3486
 
3391
 
int Heap::IterateRSetRange(Address object_start,
3392
 
                           Address object_end,
3393
 
                           Address rset_start,
3394
 
                           ObjectSlotCallback copy_object_func) {
3395
 
  Address object_address = object_start;
3396
 
  Address rset_address = rset_start;
3397
 
  int set_bits_count = 0;
3398
 
 
3399
 
  // Loop over all the pointers in [object_start, object_end).
3400
 
  while (object_address < object_end) {
3401
 
    uint32_t rset_word = Memory::uint32_at(rset_address);
3402
 
    if (rset_word != 0) {
3403
 
      uint32_t result_rset = rset_word;
3404
 
      for (uint32_t bitmask = 1; bitmask != 0; bitmask = bitmask << 1) {
3405
 
        // Do not dereference pointers at or past object_end.
3406
 
        if ((rset_word & bitmask) != 0 && object_address < object_end) {
3407
 
          Object** object_p = reinterpret_cast<Object**>(object_address);
3408
 
          if (Heap::InNewSpace(*object_p)) {
3409
 
            copy_object_func(reinterpret_cast<HeapObject**>(object_p));
3410
 
          }
3411
 
          // If this pointer does not need to be remembered anymore, clear
3412
 
          // the remembered set bit.
3413
 
          if (!Heap::InNewSpace(*object_p)) result_rset &= ~bitmask;
3414
 
          set_bits_count++;
3415
 
        }
3416
 
        object_address += kPointerSize;
3417
 
      }
3418
 
      // Update the remembered set if it has changed.
3419
 
      if (result_rset != rset_word) {
3420
 
        Memory::uint32_at(rset_address) = result_rset;
3421
 
      }
3422
 
    } else {
3423
 
      // No bits in the word were set.  This is the common case.
3424
 
      object_address += kPointerSize * kBitsPerInt;
3425
 
    }
3426
 
    rset_address += kIntSize;
3427
 
  }
3428
 
  return set_bits_count;
3429
 
}
3430
 
 
3431
 
 
3432
 
void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
3433
 
  ASSERT(Page::is_rset_in_use());
3434
 
  ASSERT(space == old_pointer_space_ || space == map_space_);
3435
 
 
3436
 
  static void* paged_rset_histogram = StatsTable::CreateHistogram(
3437
 
      "V8.RSetPaged",
3438
 
      0,
3439
 
      Page::kObjectAreaSize / kPointerSize,
3440
 
      30);
 
3487
bool Heap::IteratePointersInDirtyRegion(Address start,
 
3488
                                        Address end,
 
3489
                                        ObjectSlotCallback copy_object_func) {
 
3490
  Address slot_address = start;
 
3491
  bool pointers_to_new_space_found = false;
 
3492
 
 
3493
  while (slot_address < end) {
 
3494
    Object** slot = reinterpret_cast<Object**>(slot_address);
 
3495
    if (Heap::InNewSpace(*slot)) {
 
3496
      ASSERT((*slot)->IsHeapObject());
 
3497
      copy_object_func(reinterpret_cast<HeapObject**>(slot));
 
3498
      if (Heap::InNewSpace(*slot)) {
 
3499
        ASSERT((*slot)->IsHeapObject());
 
3500
        pointers_to_new_space_found = true;
 
3501
      }
 
3502
    }
 
3503
    slot_address += kPointerSize;
 
3504
  }
 
3505
  return pointers_to_new_space_found;
 
3506
}
 
3507
 
 
3508
 
 
3509
// Compute start address of the first map following given addr.
 
3510
static inline Address MapStartAlign(Address addr) {
 
3511
  Address page = Page::FromAddress(addr)->ObjectAreaStart();
 
3512
  return page + (((addr - page) + (Map::kSize - 1)) / Map::kSize * Map::kSize);
 
3513
}
 
3514
 
 
3515
 
 
3516
// Compute end address of the first map preceding given addr.
 
3517
static inline Address MapEndAlign(Address addr) {
 
3518
  Address page = Page::FromAllocationTop(addr)->ObjectAreaStart();
 
3519
  return page + ((addr - page) / Map::kSize * Map::kSize);
 
3520
}
 
3521
 
 
3522
 
 
3523
static bool IteratePointersInDirtyMaps(Address start,
 
3524
                                       Address end,
 
3525
                                       ObjectSlotCallback copy_object_func) {
 
3526
  ASSERT(MapStartAlign(start) == start);
 
3527
  ASSERT(MapEndAlign(end) == end);
 
3528
 
 
3529
  Address map_address = start;
 
3530
  bool pointers_to_new_space_found = false;
 
3531
 
 
3532
  while (map_address < end) {
 
3533
    ASSERT(!Heap::InNewSpace(Memory::Object_at(map_address)));
 
3534
    ASSERT(Memory::Object_at(map_address)->IsMap());
 
3535
 
 
3536
    Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset;
 
3537
    Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset;
 
3538
 
 
3539
    if (Heap::IteratePointersInDirtyRegion(pointer_fields_start,
 
3540
                                           pointer_fields_end,
 
3541
                                           copy_object_func)) {
 
3542
      pointers_to_new_space_found = true;
 
3543
    }
 
3544
 
 
3545
    map_address += Map::kSize;
 
3546
  }
 
3547
 
 
3548
  return pointers_to_new_space_found;
 
3549
}
 
3550
 
 
3551
 
 
3552
bool Heap::IteratePointersInDirtyMapsRegion(
 
3553
    Address start,
 
3554
    Address end,
 
3555
    ObjectSlotCallback copy_object_func) {
 
3556
  Address map_aligned_start = MapStartAlign(start);
 
3557
  Address map_aligned_end   = MapEndAlign(end);
 
3558
 
 
3559
  bool contains_pointers_to_new_space = false;
 
3560
 
 
3561
  if (map_aligned_start != start) {
 
3562
    Address prev_map = map_aligned_start - Map::kSize;
 
3563
    ASSERT(Memory::Object_at(prev_map)->IsMap());
 
3564
 
 
3565
    Address pointer_fields_start =
 
3566
        Max(start, prev_map + Map::kPointerFieldsBeginOffset);
 
3567
 
 
3568
    Address pointer_fields_end =
 
3569
        Min(prev_map + Map::kCodeCacheOffset + kPointerSize, end);
 
3570
 
 
3571
    contains_pointers_to_new_space =
 
3572
      IteratePointersInDirtyRegion(pointer_fields_start,
 
3573
                                   pointer_fields_end,
 
3574
                                   copy_object_func)
 
3575
        || contains_pointers_to_new_space;
 
3576
  }
 
3577
 
 
3578
  contains_pointers_to_new_space =
 
3579
    IteratePointersInDirtyMaps(map_aligned_start,
 
3580
                               map_aligned_end,
 
3581
                               copy_object_func)
 
3582
      || contains_pointers_to_new_space;
 
3583
 
 
3584
  if (map_aligned_end != end) {
 
3585
    ASSERT(Memory::Object_at(map_aligned_end)->IsMap());
 
3586
 
 
3587
    Address pointer_fields_start = map_aligned_end + Map::kPrototypeOffset;
 
3588
 
 
3589
    Address pointer_fields_end =
 
3590
        Min(end, map_aligned_end + Map::kCodeCacheOffset + kPointerSize);
 
3591
 
 
3592
    contains_pointers_to_new_space =
 
3593
      IteratePointersInDirtyRegion(pointer_fields_start,
 
3594
                                   pointer_fields_end,
 
3595
                                   copy_object_func)
 
3596
        || contains_pointers_to_new_space;
 
3597
  }
 
3598
 
 
3599
  return contains_pointers_to_new_space;
 
3600
}
 
3601
 
 
3602
 
 
3603
void Heap::IterateAndMarkPointersToNewSpace(Address start,
 
3604
                                            Address end,
 
3605
                                            ObjectSlotCallback callback) {
 
3606
  Address slot_address = start;
 
3607
  Page* page = Page::FromAddress(start);
 
3608
 
 
3609
  uint32_t marks = page->GetRegionMarks();
 
3610
 
 
3611
  while (slot_address < end) {
 
3612
    Object** slot = reinterpret_cast<Object**>(slot_address);
 
3613
    if (Heap::InNewSpace(*slot)) {
 
3614
      ASSERT((*slot)->IsHeapObject());
 
3615
      callback(reinterpret_cast<HeapObject**>(slot));
 
3616
      if (Heap::InNewSpace(*slot)) {
 
3617
        ASSERT((*slot)->IsHeapObject());
 
3618
        marks |= page->GetRegionMaskForAddress(slot_address);
 
3619
      }
 
3620
    }
 
3621
    slot_address += kPointerSize;
 
3622
  }
 
3623
 
 
3624
  page->SetRegionMarks(marks);
 
3625
}
 
3626
 
 
3627
 
 
3628
uint32_t Heap::IterateDirtyRegions(
 
3629
    uint32_t marks,
 
3630
    Address area_start,
 
3631
    Address area_end,
 
3632
    DirtyRegionCallback visit_dirty_region,
 
3633
    ObjectSlotCallback copy_object_func) {
 
3634
  uint32_t newmarks = 0;
 
3635
  uint32_t mask = 1;
 
3636
 
 
3637
  if (area_start >= area_end) {
 
3638
    return newmarks;
 
3639
  }
 
3640
 
 
3641
  Address region_start = area_start;
 
3642
 
 
3643
  // area_start does not necessarily coincide with start of the first region.
 
3644
  // Thus to calculate the beginning of the next region we have to align
 
3645
  // area_start by Page::kRegionSize.
 
3646
  Address second_region =
 
3647
      reinterpret_cast<Address>(
 
3648
          reinterpret_cast<intptr_t>(area_start + Page::kRegionSize) &
 
3649
          ~Page::kRegionAlignmentMask);
 
3650
 
 
3651
  // Next region might be beyond area_end.
 
3652
  Address region_end = Min(second_region, area_end);
 
3653
 
 
3654
  if (marks & mask) {
 
3655
    if (visit_dirty_region(region_start, region_end, copy_object_func)) {
 
3656
      newmarks |= mask;
 
3657
    }
 
3658
  }
 
3659
  mask <<= 1;
 
3660
 
 
3661
  // Iterate subsequent regions which fully lay inside [area_start, area_end[.
 
3662
  region_start = region_end;
 
3663
  region_end = region_start + Page::kRegionSize;
 
3664
 
 
3665
  while (region_end <= area_end) {
 
3666
    if (marks & mask) {
 
3667
      if (visit_dirty_region(region_start, region_end, copy_object_func)) {
 
3668
        newmarks |= mask;
 
3669
      }
 
3670
    }
 
3671
 
 
3672
    region_start = region_end;
 
3673
    region_end = region_start + Page::kRegionSize;
 
3674
 
 
3675
    mask <<= 1;
 
3676
  }
 
3677
 
 
3678
  if (region_start != area_end) {
 
3679
    // A small piece of area left uniterated because area_end does not coincide
 
3680
    // with region end. Check whether region covering last part of area is
 
3681
    // dirty.
 
3682
    if (marks & mask) {
 
3683
      if (visit_dirty_region(region_start, area_end, copy_object_func)) {
 
3684
        newmarks |= mask;
 
3685
      }
 
3686
    }
 
3687
  }
 
3688
 
 
3689
  return newmarks;
 
3690
}
 
3691
 
 
3692
 
 
3693
 
 
3694
void Heap::IterateDirtyRegions(
 
3695
    PagedSpace* space,
 
3696
    DirtyRegionCallback visit_dirty_region,
 
3697
    ObjectSlotCallback copy_object_func,
 
3698
    ExpectedPageWatermarkState expected_page_watermark_state) {
3441
3699
 
3442
3700
  PageIterator it(space, PageIterator::PAGES_IN_USE);
 
3701
 
3443
3702
  while (it.has_next()) {
3444
3703
    Page* page = it.next();
3445
 
    int count = IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(),
3446
 
                                 page->RSetStart(), copy_object_func);
3447
 
    if (paged_rset_histogram != NULL) {
3448
 
      StatsTable::AddHistogramSample(paged_rset_histogram, count);
 
3704
    uint32_t marks = page->GetRegionMarks();
 
3705
 
 
3706
    if (marks != Page::kAllRegionsCleanMarks) {
 
3707
      Address start = page->ObjectAreaStart();
 
3708
 
 
3709
      // Do not try to visit pointers beyond page allocation watermark.
 
3710
      // Page can contain garbage pointers there.
 
3711
      Address end;
 
3712
 
 
3713
      if ((expected_page_watermark_state == WATERMARK_SHOULD_BE_VALID) ||
 
3714
          page->IsWatermarkValid()) {
 
3715
        end = page->AllocationWatermark();
 
3716
      } else {
 
3717
        end = page->CachedAllocationWatermark();
 
3718
      }
 
3719
 
 
3720
      ASSERT(space == old_pointer_space_ ||
 
3721
             (space == map_space_ &&
 
3722
              ((page->ObjectAreaStart() - end) % Map::kSize == 0)));
 
3723
 
 
3724
      page->SetRegionMarks(IterateDirtyRegions(marks,
 
3725
                                               start,
 
3726
                                               end,
 
3727
                                               visit_dirty_region,
 
3728
                                               copy_object_func));
3449
3729
    }
 
3730
 
 
3731
    // Mark page watermark as invalid to maintain watermark validity invariant.
 
3732
    // See Page::FlipMeaningOfInvalidatedWatermarkFlag() for details.
 
3733
    page->InvalidateWatermark(true);
3450
3734
  }
3451
3735
}
3452
3736
 
3731
4015
 
3732
4016
 
3733
4017
void Heap::TearDown() {
 
4018
  if (FLAG_print_cumulative_gc_stat) {
 
4019
    PrintF("\n\n");
 
4020
    PrintF("gc_count=%d ", gc_count_);
 
4021
    PrintF("mark_sweep_count=%d ", ms_count_);
 
4022
    PrintF("mark_compact_count=%d ", mc_count_);
 
4023
    PrintF("max_gc_pause=%d ", GCTracer::get_max_gc_pause());
 
4024
    PrintF("min_in_mutator=%d ", GCTracer::get_min_in_mutator());
 
4025
    PrintF("max_alive_after_gc=%d ", GCTracer::get_max_alive_after_gc());
 
4026
    PrintF("\n\n");
 
4027
  }
 
4028
 
3734
4029
  GlobalHandles::TearDown();
3735
4030
 
3736
4031
  ExternalStringTable::TearDown();
4206
4501
#endif
4207
4502
 
4208
4503
 
 
4504
static int CountTotalHolesSize() {
 
4505
  int holes_size = 0;
 
4506
  OldSpaces spaces;
 
4507
  for (OldSpace* space = spaces.next();
 
4508
       space != NULL;
 
4509
       space = spaces.next()) {
 
4510
    holes_size += space->Waste() + space->AvailableFree();
 
4511
  }
 
4512
  return holes_size;
 
4513
}
 
4514
 
 
4515
 
4209
4516
GCTracer::GCTracer()
4210
4517
    : start_time_(0.0),
4211
 
      start_size_(0.0),
4212
 
      external_time_(0.0),
 
4518
      start_size_(0),
4213
4519
      gc_count_(0),
4214
4520
      full_gc_count_(0),
4215
4521
      is_compacting_(false),
4216
 
      marked_count_(0) {
 
4522
      marked_count_(0),
 
4523
      allocated_since_last_gc_(0),
 
4524
      spent_in_mutator_(0),
 
4525
      promoted_objects_size_(0) {
4217
4526
  // These two fields reflect the state of the previous full collection.
4218
4527
  // Set them before they are changed by the collector.
4219
4528
  previous_has_compacted_ = MarkCompactCollector::HasCompacted();
4220
4529
  previous_marked_count_ = MarkCompactCollector::previous_marked_count();
4221
 
  if (!FLAG_trace_gc) return;
 
4530
  if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
4222
4531
  start_time_ = OS::TimeCurrentMillis();
4223
 
  start_size_ = SizeOfHeapObjects();
 
4532
  start_size_ = Heap::SizeOfObjects();
 
4533
 
 
4534
  for (int i = 0; i < Scope::kNumberOfScopes; i++) {
 
4535
    scopes_[i] = 0;
 
4536
  }
 
4537
 
 
4538
  in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
 
4539
 
 
4540
  allocated_since_last_gc_ = Heap::SizeOfObjects() - alive_after_last_gc_;
 
4541
 
 
4542
  if (last_gc_end_timestamp_ > 0) {
 
4543
    spent_in_mutator_ = Max(start_time_ - last_gc_end_timestamp_, 0.0);
 
4544
  }
4224
4545
}
4225
4546
 
4226
4547
 
4227
4548
GCTracer::~GCTracer() {
4228
 
  if (!FLAG_trace_gc) return;
4229
4549
  // Printf ONE line iff flag is set.
4230
 
  int time = static_cast<int>(OS::TimeCurrentMillis() - start_time_);
4231
 
  int external_time = static_cast<int>(external_time_);
4232
 
  PrintF("%s %.1f -> %.1f MB, ",
4233
 
         CollectorString(), start_size_, SizeOfHeapObjects());
4234
 
  if (external_time > 0) PrintF("%d / ", external_time);
4235
 
  PrintF("%d ms.\n", time);
 
4550
  if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
 
4551
 
 
4552
  bool first_gc = (last_gc_end_timestamp_ == 0);
 
4553
 
 
4554
  alive_after_last_gc_ = Heap::SizeOfObjects();
 
4555
  last_gc_end_timestamp_ = OS::TimeCurrentMillis();
 
4556
 
 
4557
  int time = static_cast<int>(last_gc_end_timestamp_ - start_time_);
 
4558
 
 
4559
  // Update cumulative GC statistics if required.
 
4560
  if (FLAG_print_cumulative_gc_stat) {
 
4561
    max_gc_pause_ = Max(max_gc_pause_, time);
 
4562
    max_alive_after_gc_ = Max(max_alive_after_gc_, alive_after_last_gc_);
 
4563
    if (!first_gc) {
 
4564
      min_in_mutator_ = Min(min_in_mutator_,
 
4565
                            static_cast<int>(spent_in_mutator_));
 
4566
    }
 
4567
  }
 
4568
 
 
4569
  if (!FLAG_trace_gc_nvp) {
 
4570
    int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
 
4571
 
 
4572
    PrintF("%s %.1f -> %.1f MB, ",
 
4573
           CollectorString(),
 
4574
           static_cast<double>(start_size_) / MB,
 
4575
           SizeOfHeapObjects());
 
4576
 
 
4577
    if (external_time > 0) PrintF("%d / ", external_time);
 
4578
    PrintF("%d ms.\n", time);
 
4579
  } else {
 
4580
    PrintF("pause=%d ", time);
 
4581
    PrintF("mutator=%d ",
 
4582
           static_cast<int>(spent_in_mutator_));
 
4583
 
 
4584
    PrintF("gc=");
 
4585
    switch (collector_) {
 
4586
      case SCAVENGER:
 
4587
        PrintF("s");
 
4588
        break;
 
4589
      case MARK_COMPACTOR:
 
4590
        PrintF(MarkCompactCollector::HasCompacted() ? "mc" : "ms");
 
4591
        break;
 
4592
      default:
 
4593
        UNREACHABLE();
 
4594
    }
 
4595
    PrintF(" ");
 
4596
 
 
4597
    PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
 
4598
    PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
 
4599
    PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
 
4600
    PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT]));
 
4601
 
 
4602
    PrintF("total_size_before=%d ", start_size_);
 
4603
    PrintF("total_size_after=%d ", Heap::SizeOfObjects());
 
4604
    PrintF("holes_size_before=%d ", in_free_list_or_wasted_before_gc_);
 
4605
    PrintF("holes_size_after=%d ", CountTotalHolesSize());
 
4606
 
 
4607
    PrintF("allocated=%d ", allocated_since_last_gc_);
 
4608
    PrintF("promoted=%d ", promoted_objects_size_);
 
4609
 
 
4610
    PrintF("\n");
 
4611
  }
4236
4612
 
4237
4613
#if defined(ENABLE_LOGGING_AND_PROFILING)
4238
4614
  Heap::PrintShortHeapStatistics();