| Index: src/heap.h
|
| ===================================================================
|
| --- src/heap.h (revision 9531)
|
| +++ src/heap.h (working copy)
|
| @@ -32,11 +32,15 @@
|
|
|
| #include "allocation.h"
|
| #include "globals.h"
|
| +#include "incremental-marking.h"
|
| #include "list.h"
|
| #include "mark-compact.h"
|
| +#include "objects-visiting.h"
|
| #include "spaces.h"
|
| #include "splay-tree-inl.h"
|
| +#include "store-buffer.h"
|
| #include "v8-counters.h"
|
| +#include "v8globals.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -49,19 +53,19 @@
|
|
|
| // Defines all the roots in Heap.
|
| #define STRONG_ROOT_LIST(V) \
|
| - /* Put the byte array map early. We need it to be in place by the time */ \
|
| - /* the deserializer hits the next page, since it wants to put a byte */ \
|
| - /* array in the unused space at the end of the page. */ \
|
| V(Map, byte_array_map, ByteArrayMap) \
|
| + V(Map, free_space_map, FreeSpaceMap) \
|
| V(Map, one_pointer_filler_map, OnePointerFillerMap) \
|
| V(Map, two_pointer_filler_map, TwoPointerFillerMap) \
|
| /* Cluster the most popular ones in a few cache lines here at the top. */ \
|
| + V(Smi, store_buffer_top, StoreBufferTop) \
|
| V(Object, undefined_value, UndefinedValue) \
|
| V(Object, the_hole_value, TheHoleValue) \
|
| V(Object, null_value, NullValue) \
|
| V(Object, true_value, TrueValue) \
|
| V(Object, false_value, FalseValue) \
|
| V(Object, arguments_marker, ArgumentsMarker) \
|
| + V(Object, frame_alignment_marker, FrameAlignmentMarker) \
|
| V(Map, heap_number_map, HeapNumberMap) \
|
| V(Map, global_context_map, GlobalContextMap) \
|
| V(Map, fixed_array_map, FixedArrayMap) \
|
| @@ -123,6 +127,7 @@
|
| V(Map, message_object_map, JSMessageObjectMap) \
|
| V(Map, foreign_map, ForeignMap) \
|
| V(Object, nan_value, NanValue) \
|
| + V(Object, infinity_value, InfinityValue) \
|
| V(Object, minus_zero_value, MinusZeroValue) \
|
| V(Map, neander_map, NeanderMap) \
|
| V(JSObject, message_listeners, MessageListeners) \
|
| @@ -226,7 +231,9 @@
|
| V(closure_symbol, "(closure)") \
|
| V(use_strict, "use strict") \
|
| V(dot_symbol, ".") \
|
| - V(anonymous_function_symbol, "(anonymous function)")
|
| + V(anonymous_function_symbol, "(anonymous function)") \
|
| + V(infinity_symbol, "Infinity") \
|
| + V(minus_infinity_symbol, "-Infinity")
|
|
|
| // Forward declarations.
|
| class GCTracer;
|
| @@ -238,12 +245,28 @@
|
| typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
|
| Object** pointer);
|
|
|
| -typedef bool (*DirtyRegionCallback)(Heap* heap,
|
| - Address start,
|
| - Address end,
|
| - ObjectSlotCallback copy_object_func);
|
| +class StoreBufferRebuilder {
|
| + public:
|
| + explicit StoreBufferRebuilder(StoreBuffer* store_buffer)
|
| + : store_buffer_(store_buffer) {
|
| + }
|
|
|
| + void Callback(MemoryChunk* page, StoreBufferEvent event);
|
|
|
| + private:
|
| + StoreBuffer* store_buffer_;
|
| +
|
| + // We record in this variable how full the store buffer was when we started
|
| + // iterating over the current page, finding pointers to new space. If the
|
| + // store buffer overflows again we can exempt the page from the store buffer
|
| + // by rewinding to this point instead of having to search the store buffer.
|
| + Object*** start_of_current_page_;
|
| + // The current page we are scanning in the store buffer iterator.
|
| + MemoryChunk* current_page_;
|
| +};
|
| +
|
| +
|
| +
|
| // The all static Heap captures the interface to the global object heap.
|
| // All JavaScript contexts by this process share the same object heap.
|
|
|
| @@ -259,22 +282,37 @@
|
| PromotionQueue() : front_(NULL), rear_(NULL) { }
|
|
|
| void Initialize(Address start_address) {
|
| + // Assumes that a NewSpacePage exactly fits a number of promotion queue
|
| + // entries (where each is a pair of intptr_t). This allows us to simplify
|
| + // the test fpr when to switch pages.
|
| + ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
|
| + == 0);
|
| + ASSERT(NewSpacePage::IsAtEnd(start_address));
|
| front_ = rear_ = reinterpret_cast<intptr_t*>(start_address);
|
| }
|
|
|
| - bool is_empty() { return front_ <= rear_; }
|
| + bool is_empty() { return front_ == rear_; }
|
|
|
| inline void insert(HeapObject* target, int size);
|
|
|
| void remove(HeapObject** target, int* size) {
|
| + ASSERT(!is_empty());
|
| + if (NewSpacePage::IsAtStart(reinterpret_cast<Address>(front_))) {
|
| + NewSpacePage* front_page =
|
| + NewSpacePage::FromAddress(reinterpret_cast<Address>(front_));
|
| + ASSERT(!front_page->prev_page()->is_anchor());
|
| + front_ =
|
| + reinterpret_cast<intptr_t*>(front_page->prev_page()->body_limit());
|
| + }
|
| *target = reinterpret_cast<HeapObject*>(*(--front_));
|
| *size = static_cast<int>(*(--front_));
|
| // Assert no underflow.
|
| - ASSERT(front_ >= rear_);
|
| + SemiSpace::AssertValidRange(reinterpret_cast<Address>(rear_),
|
| + reinterpret_cast<Address>(front_));
|
| }
|
|
|
| private:
|
| - // The front of the queue is higher in memory than the rear.
|
| + // The front of the queue is higher in the memory page chain than the rear.
|
| intptr_t* front_;
|
| intptr_t* rear_;
|
|
|
| @@ -282,6 +320,11 @@
|
| };
|
|
|
|
|
| +typedef void (*ScavengingCallback)(Map* map,
|
| + HeapObject** slot,
|
| + HeapObject* object);
|
| +
|
| +
|
| // External strings table is a place where all external strings are
|
| // registered. We need to keep track of such strings to properly
|
| // finalize them.
|
| @@ -327,8 +370,8 @@
|
| // Configure heap size before setup. Return false if the heap has been
|
| // setup already.
|
| bool ConfigureHeap(int max_semispace_size,
|
| - int max_old_gen_size,
|
| - int max_executable_size);
|
| + intptr_t max_old_gen_size,
|
| + intptr_t max_executable_size);
|
| bool ConfigureHeapDefault();
|
|
|
| // Initializes the global object heap. If create_heap_objects is true,
|
| @@ -456,6 +499,7 @@
|
| // size, but keeping the original prototype. The receiver must have at least
|
| // the size of the new object. The object is reinitialized and behaves as an
|
| // object that has been freshly allocated.
|
| + // Returns failure if an error occured, otherwise object.
|
| MUST_USE_RESULT MaybeObject* ReinitializeJSReceiver(JSReceiver* object,
|
| InstanceType type,
|
| int size);
|
| @@ -484,8 +528,10 @@
|
| // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
|
| // failed.
|
| // Please note this function does not perform a garbage collection.
|
| - MUST_USE_RESULT MaybeObject* AllocateMap(InstanceType instance_type,
|
| - int instance_size);
|
| + MUST_USE_RESULT MaybeObject* AllocateMap(
|
| + InstanceType instance_type,
|
| + int instance_size,
|
| + ElementsKind elements_kind = FAST_ELEMENTS);
|
|
|
| // Allocates a partial map for bootstrapping.
|
| MUST_USE_RESULT MaybeObject* AllocatePartialMap(InstanceType instance_type,
|
| @@ -796,9 +842,9 @@
|
| // failed.
|
| // Please note this does not perform a garbage collection.
|
| MUST_USE_RESULT MaybeObject* AllocateExternalStringFromAscii(
|
| - ExternalAsciiString::Resource* resource);
|
| + const ExternalAsciiString::Resource* resource);
|
| MUST_USE_RESULT MaybeObject* AllocateExternalStringFromTwoByte(
|
| - ExternalTwoByteString::Resource* resource);
|
| + const ExternalTwoByteString::Resource* resource);
|
|
|
| // Finalizes an external string by deleting the associated external
|
| // data and clearing the resource pointer.
|
| @@ -885,13 +931,24 @@
|
| // collect more garbage.
|
| inline bool CollectGarbage(AllocationSpace space);
|
|
|
| - // Performs a full garbage collection. Force compaction if the
|
| - // parameter is true.
|
| - void CollectAllGarbage(bool force_compaction);
|
| + static const int kNoGCFlags = 0;
|
| + static const int kMakeHeapIterableMask = 1;
|
|
|
| + // Performs a full garbage collection. If (flags & kMakeHeapIterableMask) is
|
| + // non-zero, then the slower precise sweeper is used, which leaves the heap
|
| + // in a state where we can iterate over the heap visiting all objects.
|
| + void CollectAllGarbage(int flags);
|
| +
|
| // Last hope GC, should try to squeeze as much as possible.
|
| void CollectAllAvailableGarbage();
|
|
|
| + // Check whether the heap is currently iterable.
|
| + bool IsHeapIterable();
|
| +
|
| + // Ensure that we have swept all spaces in such a way that we can iterate
|
| + // over all objects. May cause a GC.
|
| + void EnsureHeapIsIterable();
|
| +
|
| // Notify the heap that a context has been disposed.
|
| int NotifyContextDisposed() { return ++contexts_disposed_; }
|
|
|
| @@ -899,6 +956,20 @@
|
| // ensure correct callback for weak global handles.
|
| void PerformScavenge();
|
|
|
| + inline void increment_scan_on_scavenge_pages() {
|
| + scan_on_scavenge_pages_++;
|
| + if (FLAG_gc_verbose) {
|
| + PrintF("Scan-on-scavenge pages: %d\n", scan_on_scavenge_pages_);
|
| + }
|
| + }
|
| +
|
| + inline void decrement_scan_on_scavenge_pages() {
|
| + scan_on_scavenge_pages_--;
|
| + if (FLAG_gc_verbose) {
|
| + PrintF("Scan-on-scavenge pages: %d\n", scan_on_scavenge_pages_);
|
| + }
|
| + }
|
| +
|
| PromotionQueue* promotion_queue() { return &promotion_queue_; }
|
|
|
| #ifdef DEBUG
|
| @@ -925,6 +996,8 @@
|
|
|
| // Heap root getters. We have versions with and without type::cast() here.
|
| // You can't use type::cast during GC because the assert fails.
|
| + // TODO(1490): Try removing the unchecked accessors, now that GC marking does
|
| + // not corrupt the stack.
|
| #define ROOT_ACCESSOR(type, name, camel_name) \
|
| type* name() { \
|
| return type::cast(roots_[k##camel_name##RootIndex]); \
|
| @@ -965,60 +1038,16 @@
|
| // Iterates over all the other roots in the heap.
|
| void IterateWeakRoots(ObjectVisitor* v, VisitMode mode);
|
|
|
| - enum ExpectedPageWatermarkState {
|
| - WATERMARK_SHOULD_BE_VALID,
|
| - WATERMARK_CAN_BE_INVALID
|
| - };
|
| -
|
| - // For each dirty region on a page in use from an old space call
|
| - // visit_dirty_region callback.
|
| - // If either visit_dirty_region or callback can cause an allocation
|
| - // in old space and changes in allocation watermark then
|
| - // can_preallocate_during_iteration should be set to true.
|
| - // All pages will be marked as having invalid watermark upon
|
| - // iteration completion.
|
| - void IterateDirtyRegions(
|
| - PagedSpace* space,
|
| - DirtyRegionCallback visit_dirty_region,
|
| - ObjectSlotCallback callback,
|
| - ExpectedPageWatermarkState expected_page_watermark_state);
|
| -
|
| - // Interpret marks as a bitvector of dirty marks for regions of size
|
| - // Page::kRegionSize aligned by Page::kRegionAlignmentMask and covering
|
| - // memory interval from start to top. For each dirty region call a
|
| - // visit_dirty_region callback. Return updated bitvector of dirty marks.
|
| - uint32_t IterateDirtyRegions(uint32_t marks,
|
| - Address start,
|
| - Address end,
|
| - DirtyRegionCallback visit_dirty_region,
|
| - ObjectSlotCallback callback);
|
| -
|
| // Iterate pointers to from semispace of new space found in memory interval
|
| // from start to end.
|
| - // Update dirty marks for page containing start address.
|
| void IterateAndMarkPointersToFromSpace(Address start,
|
| Address end,
|
| ObjectSlotCallback callback);
|
|
|
| - // Iterate pointers to new space found in memory interval from start to end.
|
| - // Return true if pointers to new space was found.
|
| - static bool IteratePointersInDirtyRegion(Heap* heap,
|
| - Address start,
|
| - Address end,
|
| - ObjectSlotCallback callback);
|
| -
|
| -
|
| - // Iterate pointers to new space found in memory interval from start to end.
|
| - // This interval is considered to belong to the map space.
|
| - // Return true if pointers to new space was found.
|
| - static bool IteratePointersInDirtyMapsRegion(Heap* heap,
|
| - Address start,
|
| - Address end,
|
| - ObjectSlotCallback callback);
|
| -
|
| -
|
| // Returns whether the object resides in new space.
|
| inline bool InNewSpace(Object* object);
|
| + inline bool InNewSpace(Address addr);
|
| + inline bool InNewSpacePage(Address addr);
|
| inline bool InFromSpace(Object* object);
|
| inline bool InToSpace(Object* object);
|
|
|
| @@ -1057,12 +1086,20 @@
|
| roots_[kEmptyScriptRootIndex] = script;
|
| }
|
|
|
| + void public_set_store_buffer_top(Address* top) {
|
| + roots_[kStoreBufferTopRootIndex] = reinterpret_cast<Smi*>(top);
|
| + }
|
| +
|
| // Update the next script id.
|
| inline void SetLastScriptId(Object* last_script_id);
|
|
|
| // Generated code can embed this address to get access to the roots.
|
| Object** roots_address() { return roots_; }
|
|
|
| + Address* store_buffer_top_address() {
|
| + return reinterpret_cast<Address*>(&roots_[kStoreBufferTopRootIndex]);
|
| + }
|
| +
|
| // Get address of global contexts list for serialization support.
|
| Object** global_contexts_list_address() {
|
| return &global_contexts_list_;
|
| @@ -1075,6 +1112,10 @@
|
| // Verify the heap is in its normal state before or after a GC.
|
| void Verify();
|
|
|
| + void OldPointerSpaceCheckStoreBuffer();
|
| + void MapSpaceCheckStoreBuffer();
|
| + void LargeObjectSpaceCheckStoreBuffer();
|
| +
|
| // Report heap statistics.
|
| void ReportHeapStatistics(const char* title);
|
| void ReportCodeStatistics(const char* title);
|
| @@ -1170,24 +1211,53 @@
|
| MUST_USE_RESULT MaybeObject* AllocateRawFixedArray(int length,
|
| PretenureFlag pretenure);
|
|
|
| + inline intptr_t PromotedTotalSize() {
|
| + return PromotedSpaceSize() + PromotedExternalMemorySize();
|
| + }
|
| +
|
| // True if we have reached the allocation limit in the old generation that
|
| // should force the next GC (caused normally) to be a full one.
|
| - bool OldGenerationPromotionLimitReached() {
|
| - return (PromotedSpaceSize() + PromotedExternalMemorySize())
|
| - > old_gen_promotion_limit_;
|
| + inline bool OldGenerationPromotionLimitReached() {
|
| + return PromotedTotalSize() > old_gen_promotion_limit_;
|
| }
|
|
|
| - intptr_t OldGenerationSpaceAvailable() {
|
| - return old_gen_allocation_limit_ -
|
| - (PromotedSpaceSize() + PromotedExternalMemorySize());
|
| + inline intptr_t OldGenerationSpaceAvailable() {
|
| + return old_gen_allocation_limit_ - PromotedTotalSize();
|
| }
|
|
|
| - // True if we have reached the allocation limit in the old generation that
|
| - // should artificially cause a GC right now.
|
| - bool OldGenerationAllocationLimitReached() {
|
| - return OldGenerationSpaceAvailable() < 0;
|
| + static const intptr_t kMinimumPromotionLimit = 5 * Page::kPageSize;
|
| + static const intptr_t kMinimumAllocationLimit =
|
| + 8 * (Page::kPageSize > MB ? Page::kPageSize : MB);
|
| +
|
| + // When we sweep lazily we initially guess that there is no garbage on the
|
| + // heap and set the limits for the next GC accordingly. As we sweep we find
|
| + // out that some of the pages contained garbage and we have to adjust
|
| + // downwards the size of the heap. This means the limits that control the
|
| + // timing of the next GC also need to be adjusted downwards.
|
| + void LowerOldGenLimits(intptr_t adjustment) {
|
| + size_of_old_gen_at_last_old_space_gc_ -= adjustment;
|
| + old_gen_promotion_limit_ =
|
| + OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
|
| + old_gen_allocation_limit_ =
|
| + OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
|
| }
|
|
|
| + intptr_t OldGenPromotionLimit(intptr_t old_gen_size) {
|
| + intptr_t limit =
|
| + Max(old_gen_size + old_gen_size / 3, kMinimumPromotionLimit);
|
| + limit += new_space_.Capacity();
|
| + limit *= old_gen_limit_factor_;
|
| + return limit;
|
| + }
|
| +
|
| + intptr_t OldGenAllocationLimit(intptr_t old_gen_size) {
|
| + intptr_t limit =
|
| + Max(old_gen_size + old_gen_size / 2, kMinimumAllocationLimit);
|
| + limit += new_space_.Capacity();
|
| + limit *= old_gen_limit_factor_;
|
| + return limit;
|
| + }
|
| +
|
| // Can be called when the embedding application is idle.
|
| bool IdleNotification();
|
|
|
| @@ -1213,6 +1283,8 @@
|
|
|
| MUST_USE_RESULT MaybeObject* NumberToString(
|
| Object* number, bool check_number_string_cache = true);
|
| + MUST_USE_RESULT MaybeObject* Uint32ToString(
|
| + uint32_t value, bool check_number_string_cache = true);
|
|
|
| Map* MapForExternalArrayType(ExternalArrayType array_type);
|
| RootListIndex RootIndexForExternalArrayType(
|
| @@ -1224,18 +1296,10 @@
|
| // by pointer size.
|
| static inline void CopyBlock(Address dst, Address src, int byte_size);
|
|
|
| - inline void CopyBlockToOldSpaceAndUpdateRegionMarks(Address dst,
|
| - Address src,
|
| - int byte_size);
|
| -
|
| // Optimized version of memmove for blocks with pointer size aligned sizes and
|
| // pointer size aligned addresses.
|
| static inline void MoveBlock(Address dst, Address src, int byte_size);
|
|
|
| - inline void MoveBlockToOldSpaceAndUpdateRegionMarks(Address dst,
|
| - Address src,
|
| - int byte_size);
|
| -
|
| // Check new space expansion criteria and expand semispaces if it was hit.
|
| void CheckNewSpaceExpansionCriteria();
|
|
|
| @@ -1244,9 +1308,31 @@
|
| survived_since_last_expansion_ += survived;
|
| }
|
|
|
| + inline bool NextGCIsLikelyToBeFull() {
|
| + if (FLAG_gc_global) return true;
|
| +
|
| + intptr_t total_promoted = PromotedTotalSize();
|
| +
|
| + intptr_t adjusted_promotion_limit =
|
| + old_gen_promotion_limit_ - new_space_.Capacity();
|
| +
|
| + if (total_promoted >= adjusted_promotion_limit) return true;
|
| +
|
| + intptr_t adjusted_allocation_limit =
|
| + old_gen_allocation_limit_ - new_space_.Capacity() / 5;
|
| +
|
| + if (PromotedSpaceSize() >= adjusted_allocation_limit) return true;
|
| +
|
| + return false;
|
| + }
|
| +
|
| +
|
| void UpdateNewSpaceReferencesInExternalStringTable(
|
| ExternalStringTableUpdaterCallback updater_func);
|
|
|
| + void UpdateReferencesInExternalStringTable(
|
| + ExternalStringTableUpdaterCallback updater_func);
|
| +
|
| void ProcessWeakReferences(WeakObjectRetainer* retainer);
|
|
|
| // Helper function that governs the promotion policy from new space to
|
| @@ -1263,6 +1349,9 @@
|
|
|
| GCTracer* tracer() { return tracer_; }
|
|
|
| + // Returns the size of objects residing in non new spaces.
|
| + intptr_t PromotedSpaceSize();
|
| +
|
| double total_regexp_code_generated() { return total_regexp_code_generated_; }
|
| void IncreaseTotalRegexpCodeGenerated(int size) {
|
| total_regexp_code_generated_ += size;
|
| @@ -1281,6 +1370,18 @@
|
| return &mark_compact_collector_;
|
| }
|
|
|
| + StoreBuffer* store_buffer() {
|
| + return &store_buffer_;
|
| + }
|
| +
|
| + Marking* marking() {
|
| + return &marking_;
|
| + }
|
| +
|
| + IncrementalMarking* incremental_marking() {
|
| + return &incremental_marking_;
|
| + }
|
| +
|
| ExternalStringTable* external_string_table() {
|
| return &external_string_table_;
|
| }
|
| @@ -1291,16 +1392,28 @@
|
| }
|
|
|
| inline Isolate* isolate();
|
| - bool is_safe_to_read_maps() { return is_safe_to_read_maps_; }
|
|
|
| - void CallGlobalGCPrologueCallback() {
|
| + inline void CallGlobalGCPrologueCallback() {
|
| if (global_gc_prologue_callback_ != NULL) global_gc_prologue_callback_();
|
| }
|
|
|
| - void CallGlobalGCEpilogueCallback() {
|
| + inline void CallGlobalGCEpilogueCallback() {
|
| if (global_gc_epilogue_callback_ != NULL) global_gc_epilogue_callback_();
|
| }
|
|
|
| + inline bool OldGenerationAllocationLimitReached();
|
| +
|
| + inline void DoScavengeObject(Map* map, HeapObject** slot, HeapObject* obj) {
|
| + scavenging_visitors_table_.GetVisitor(map)(map, slot, obj);
|
| + }
|
| +
|
| + void QueueMemoryChunkForFree(MemoryChunk* chunk);
|
| + void FreeQueuedChunks();
|
| +
|
| + // Completely clear the Instanceof cache (to stop it keeping objects alive
|
| + // around a GC).
|
| + inline void CompletelyClearInstanceofCache();
|
| +
|
| private:
|
| Heap();
|
|
|
| @@ -1308,12 +1421,12 @@
|
| // more expedient to get at the isolate directly from within Heap methods.
|
| Isolate* isolate_;
|
|
|
| + intptr_t code_range_size_;
|
| int reserved_semispace_size_;
|
| int max_semispace_size_;
|
| int initial_semispace_size_;
|
| intptr_t max_old_generation_size_;
|
| intptr_t max_executable_size_;
|
| - intptr_t code_range_size_;
|
|
|
| // For keeping track of how much data has survived
|
| // scavenge since last new space expansion.
|
| @@ -1328,6 +1441,8 @@
|
| // For keeping track of context disposals.
|
| int contexts_disposed_;
|
|
|
| + int scan_on_scavenge_pages_;
|
| +
|
| #if defined(V8_TARGET_ARCH_X64)
|
| static const int kMaxObjectSizeInNewSpace = 1024*KB;
|
| #else
|
| @@ -1344,13 +1459,9 @@
|
| HeapState gc_state_;
|
| int gc_post_processing_depth_;
|
|
|
| - // Returns the size of object residing in non new spaces.
|
| - intptr_t PromotedSpaceSize();
|
| -
|
| // Returns the amount of external memory registered since last global gc.
|
| int PromotedExternalMemorySize();
|
|
|
| - int mc_count_; // how many mark-compact collections happened
|
| int ms_count_; // how many mark-sweep collections happened
|
| unsigned int gc_count_; // how many gc happened
|
|
|
| @@ -1389,6 +1500,13 @@
|
| // every allocation in large object space.
|
| intptr_t old_gen_allocation_limit_;
|
|
|
| + // Sometimes the heuristics dictate that those limits are increased. This
|
| + // variable records that fact.
|
| + int old_gen_limit_factor_;
|
| +
|
| + // Used to adjust the limits that control the timing of the next GC.
|
| + intptr_t size_of_old_gen_at_last_old_space_gc_;
|
| +
|
| // Limit on the amount of externally allocated memory allowed
|
| // between global GCs. If reached a global GC is forced.
|
| intptr_t external_allocation_limit_;
|
| @@ -1408,6 +1526,8 @@
|
|
|
| Object* global_contexts_list_;
|
|
|
| + StoreBufferRebuilder store_buffer_rebuilder_;
|
| +
|
| struct StringTypeTable {
|
| InstanceType type;
|
| int size;
|
| @@ -1465,13 +1585,11 @@
|
| // Support for computing object sizes during GC.
|
| HeapObjectCallback gc_safe_size_of_old_object_;
|
| static int GcSafeSizeOfOldObject(HeapObject* object);
|
| - static int GcSafeSizeOfOldObjectWithEncodedMap(HeapObject* object);
|
|
|
| // Update the GC state. Called from the mark-compact collector.
|
| void MarkMapPointersAsEncoded(bool encoded) {
|
| - gc_safe_size_of_old_object_ = encoded
|
| - ? &GcSafeSizeOfOldObjectWithEncodedMap
|
| - : &GcSafeSizeOfOldObject;
|
| + ASSERT(!encoded);
|
| + gc_safe_size_of_old_object_ = &GcSafeSizeOfOldObject;
|
| }
|
|
|
| // Checks whether a global GC is necessary
|
| @@ -1483,11 +1601,10 @@
|
| bool PerformGarbageCollection(GarbageCollector collector,
|
| GCTracer* tracer);
|
|
|
| - static const intptr_t kMinimumPromotionLimit = 2 * MB;
|
| - static const intptr_t kMinimumAllocationLimit = 8 * MB;
|
|
|
| inline void UpdateOldSpaceLimits();
|
|
|
| +
|
| // Allocate an uninitialized object in map space. The behavior is identical
|
| // to Heap::AllocateRaw(size_in_bytes, MAP_SPACE), except that (a) it doesn't
|
| // have to test the allocation space argument and (b) can reduce code size
|
| @@ -1522,8 +1639,6 @@
|
| // Allocate empty fixed double array.
|
| MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
|
|
|
| - void SwitchScavengingVisitorsTableIfProfilingWasEnabled();
|
| -
|
| // Performs a minor collection in new generation.
|
| void Scavenge();
|
|
|
| @@ -1532,17 +1647,16 @@
|
| Object** pointer);
|
|
|
| Address DoScavenge(ObjectVisitor* scavenge_visitor, Address new_space_front);
|
| + static void ScavengeStoreBufferCallback(Heap* heap,
|
| + MemoryChunk* page,
|
| + StoreBufferEvent event);
|
|
|
| // Performs a major collection in the whole heap.
|
| void MarkCompact(GCTracer* tracer);
|
|
|
| // Code to be run before and after mark-compact.
|
| - void MarkCompactPrologue(bool is_compacting);
|
| + void MarkCompactPrologue();
|
|
|
| - // Completely clear the Instanceof cache (to stop it keeping objects alive
|
| - // around a GC).
|
| - inline void CompletelyClearInstanceofCache();
|
| -
|
| // Record statistics before and after garbage collection.
|
| void ReportStatisticsBeforeGC();
|
| void ReportStatisticsAfterGC();
|
| @@ -1551,12 +1665,11 @@
|
| static void ScavengeObjectSlow(HeapObject** p, HeapObject* object);
|
|
|
| // Initializes a function with a shared part and prototype.
|
| - // Returns the function.
|
| // Note: this code was factored out of AllocateFunction such that
|
| // other parts of the VM could use it. Specifically, a function that creates
|
| // instances of type JS_FUNCTION_TYPE benefit from the use of this function.
|
| // Please note this does not perform a garbage collection.
|
| - MUST_USE_RESULT inline MaybeObject* InitializeFunction(
|
| + inline void InitializeFunction(
|
| JSFunction* function,
|
| SharedFunctionInfo* shared,
|
| Object* prototype);
|
| @@ -1621,6 +1734,8 @@
|
| return high_survival_rate_period_length_ > 0;
|
| }
|
|
|
| + void SelectScavengingVisitorsTable();
|
| +
|
| static const int kInitialSymbolTableSize = 2048;
|
| static const int kInitialEvalCacheSize = 64;
|
|
|
| @@ -1640,11 +1755,12 @@
|
|
|
| MarkCompactCollector mark_compact_collector_;
|
|
|
| - // This field contains the meaning of the WATERMARK_INVALIDATED flag.
|
| - // Instead of clearing this flag from all pages we just flip
|
| - // its meaning at the beginning of a scavenge.
|
| - intptr_t page_watermark_invalidated_mark_;
|
| + StoreBuffer store_buffer_;
|
|
|
| + Marking marking_;
|
| +
|
| + IncrementalMarking incremental_marking_;
|
| +
|
| int number_idle_notifications_;
|
| unsigned int last_idle_notification_gc_count_;
|
| bool last_idle_notification_gc_count_init_;
|
| @@ -1658,8 +1774,10 @@
|
|
|
| ExternalStringTable external_string_table_;
|
|
|
| - bool is_safe_to_read_maps_;
|
| + VisitorDispatchTable<ScavengingCallback> scavenging_visitors_table_;
|
|
|
| + MemoryChunk* chunks_queued_for_free_;
|
| +
|
| friend class Factory;
|
| friend class GCTracer;
|
| friend class DisallowAllocationFailure;
|
| @@ -1757,29 +1875,6 @@
|
| }
|
| }
|
| };
|
| -
|
| -
|
| -// Visitor class to verify interior pointers in spaces that use region marks
|
| -// to keep track of intergenerational references.
|
| -// As VerifyPointersVisitor but also checks that dirty marks are set
|
| -// for regions covering intergenerational references.
|
| -class VerifyPointersAndDirtyRegionsVisitor: public ObjectVisitor {
|
| - public:
|
| - void VisitPointers(Object** start, Object** end) {
|
| - for (Object** current = start; current < end; current++) {
|
| - if ((*current)->IsHeapObject()) {
|
| - HeapObject* object = HeapObject::cast(*current);
|
| - ASSERT(HEAP->Contains(object));
|
| - ASSERT(object->map()->IsMap());
|
| - if (HEAP->InNewSpace(object)) {
|
| - ASSERT(HEAP->InToSpace(object));
|
| - Address addr = reinterpret_cast<Address>(current);
|
| - ASSERT(Page::FromAddress(addr)->IsRegionDirty(addr));
|
| - }
|
| - }
|
| - }
|
| - }
|
| -};
|
| #endif
|
|
|
|
|
| @@ -2112,16 +2207,6 @@
|
| // Sets the full GC count.
|
| void set_full_gc_count(int count) { full_gc_count_ = count; }
|
|
|
| - // Sets the flag that this is a compacting full GC.
|
| - void set_is_compacting() { is_compacting_ = true; }
|
| - bool is_compacting() const { return is_compacting_; }
|
| -
|
| - // Increment and decrement the count of marked objects.
|
| - void increment_marked_count() { ++marked_count_; }
|
| - void decrement_marked_count() { --marked_count_; }
|
| -
|
| - int marked_count() { return marked_count_; }
|
| -
|
| void increment_promoted_objects_size(int object_size) {
|
| promoted_objects_size_ += object_size;
|
| }
|
| @@ -2146,23 +2231,6 @@
|
| // A count (including this one) of the number of full garbage collections.
|
| int full_gc_count_;
|
|
|
| - // True if the current GC is a compacting full collection, false
|
| - // otherwise.
|
| - bool is_compacting_;
|
| -
|
| - // True if the *previous* full GC cwas a compacting collection (will be
|
| - // false if there has not been a previous full GC).
|
| - bool previous_has_compacted_;
|
| -
|
| - // On a full GC, a count of the number of marked objects. Incremented
|
| - // when an object is marked and decremented when an object's mark bit is
|
| - // cleared. Will be zero on a scavenge collection.
|
| - int marked_count_;
|
| -
|
| - // The count from the end of the previous full GC. Will be zero if there
|
| - // was no previous full GC.
|
| - int previous_marked_count_;
|
| -
|
| // Amounts of time spent in different scopes during GC.
|
| double scopes_[Scope::kNumberOfScopes];
|
|
|
| @@ -2181,6 +2249,13 @@
|
| // Size of objects promoted during the current collection.
|
| intptr_t promoted_objects_size_;
|
|
|
| + // Incremental marking steps counters.
|
| + int steps_count_;
|
| + double steps_took_;
|
| + double longest_step_;
|
| + int steps_count_since_last_gc_;
|
| + double steps_took_since_last_gc_;
|
| +
|
| Heap* heap_;
|
| };
|
|
|
| @@ -2292,6 +2367,46 @@
|
| };
|
|
|
|
|
| +// Intrusive object marking uses least significant bit of
|
| +// heap object's map word to mark objects.
|
| +// Normally all map words have least significant bit set
|
| +// because they contain tagged map pointer.
|
| +// If the bit is not set object is marked.
|
| +// All objects should be unmarked before resuming
|
| +// JavaScript execution.
|
| +class IntrusiveMarking {
|
| + public:
|
| + static bool IsMarked(HeapObject* object) {
|
| + return (object->map_word().ToRawValue() & kNotMarkedBit) == 0;
|
| + }
|
| +
|
| + static void ClearMark(HeapObject* object) {
|
| + uintptr_t map_word = object->map_word().ToRawValue();
|
| + object->set_map_word(MapWord::FromRawValue(map_word | kNotMarkedBit));
|
| + ASSERT(!IsMarked(object));
|
| + }
|
| +
|
| + static void SetMark(HeapObject* object) {
|
| + uintptr_t map_word = object->map_word().ToRawValue();
|
| + object->set_map_word(MapWord::FromRawValue(map_word & ~kNotMarkedBit));
|
| + ASSERT(IsMarked(object));
|
| + }
|
| +
|
| + static Map* MapOfMarkedObject(HeapObject* object) {
|
| + uintptr_t map_word = object->map_word().ToRawValue();
|
| + return MapWord::FromRawValue(map_word | kNotMarkedBit).ToMap();
|
| + }
|
| +
|
| + static int SizeOfMarkedObject(HeapObject* object) {
|
| + return object->SizeFromMap(MapOfMarkedObject(object));
|
| + }
|
| +
|
| + private:
|
| + static const uintptr_t kNotMarkedBit = 0x1;
|
| + STATIC_ASSERT((kHeapObjectTag & kNotMarkedBit) != 0);
|
| +};
|
| +
|
| +
|
| #if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
|
| // Helper class for tracing paths to a search target Object from all roots.
|
| // The TracePathFrom() method can be used to trace paths from a specific
|
| @@ -2350,7 +2465,6 @@
|
| };
|
| #endif // DEBUG || LIVE_OBJECT_LIST
|
|
|
| -
|
| } } // namespace v8::internal
|
|
|
| #undef HEAP
|
|
|