From 1688876682e7ec14a5f25ce6f053a6bf8e6d031d Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Fri, 11 Jun 2010 17:03:19 +0000 Subject: [PATCH] Faster implementation of Heap::RecordWrites. Naive algorithm for to update RSets for a span is rather inefficient as it performs many unnecessary operations (retrieving a mask, updating it with the same bit as many pointers go into a single region). Review URL: http://codereview.chromium.org/2727009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4849 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/heap-inl.h | 9 +++------ src/spaces-inl.h | 27 +++++++++++++++++++++++++++ src/spaces.h | 1 + 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/heap-inl.h b/src/heap-inl.h index cc558b8248..5cb24eec2f 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -196,12 +196,9 @@ void Heap::RecordWrite(Address address, int offset) { void Heap::RecordWrites(Address address, int start, int len) { if (new_space_.Contains(address)) return; ASSERT(!new_space_.FromSpaceContains(address)); - for (int offset = start; - offset < start + len * kPointerSize; - offset += kPointerSize) { - SLOW_ASSERT(Contains(address + offset)); - Page::FromAddress(address)->MarkRegionDirty(address + offset); - } + Page* page = Page::FromAddress(address); + page->SetRegionMarks(page->GetRegionMarks() | + page->GetRegionMaskForSpan(address + start, len * kPointerSize)); } diff --git a/src/spaces-inl.h b/src/spaces-inl.h index 862d5bee5a..d49c207518 100644 --- a/src/spaces-inl.h +++ b/src/spaces-inl.h @@ -152,6 +152,33 @@ uint32_t Page::GetRegionMaskForAddress(Address addr) { } +uint32_t Page::GetRegionMaskForSpan(Address start, int length_in_bytes) { + uint32_t result = 0; + if (length_in_bytes >= kPageSize) { + result = kAllRegionsDirtyMarks; + } else if (length_in_bytes > 0) { + int start_region = GetRegionNumberForAddress(start); + int end_region = + GetRegionNumberForAddress(start + length_in_bytes - kPointerSize); + uint32_t start_mask = (~0) << start_region; + uint32_t end_mask = ~((~1) << end_region); + result = start_mask & end_mask; + // if end_region < start_region, the mask is ored. + if (result == 0) result = start_mask | end_mask; + } +#ifdef DEBUG + if (FLAG_enable_slow_asserts) { + uint32_t expected = 0; + for (Address a = start; a < start + length_in_bytes; a += kPointerSize) { + expected |= GetRegionMaskForAddress(a); + } + ASSERT(expected == result); + } +#endif + return result; +} + + void Page::MarkRegionDirty(Address address) { SetRegionMarks(GetRegionMarks() | GetRegionMaskForAddress(address)); } diff --git a/src/spaces.h b/src/spaces.h index 32a3e6cb0e..051ce37cf8 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -220,6 +220,7 @@ class Page { inline void SetRegionMarks(uint32_t dirty); inline uint32_t GetRegionMaskForAddress(Address addr); + inline uint32_t GetRegionMaskForSpan(Address start, int length_in_bytes); inline int GetRegionNumberForAddress(Address addr); inline void MarkRegionDirty(Address addr);