Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: src/heap/spaces.cc

Issue 1772733002: [heap] Move to two-level free-list (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Speed up very slow FreeList::IsVeryLong which is used in a regular DCHECK Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/heap/spaces.h" 5 #include "src/heap/spaces.h"
6 6
7 #include "src/base/bits.h" 7 #include "src/base/bits.h"
8 #include "src/base/platform/platform.h" 8 #include "src/base/platform/platform.h"
9 #include "src/full-codegen/full-codegen.h" 9 #include "src/full-codegen/full-codegen.h"
10 #include "src/heap/slot-set.h" 10 #include "src/heap/slot-set.h"
(...skipping 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 void PagedSpace::TearDown() { 1024 void PagedSpace::TearDown() {
1025 PageIterator iterator(this); 1025 PageIterator iterator(this);
1026 while (iterator.has_next()) { 1026 while (iterator.has_next()) {
1027 heap()->isolate()->memory_allocator()->Free(iterator.next()); 1027 heap()->isolate()->memory_allocator()->Free(iterator.next());
1028 } 1028 }
1029 anchor_.set_next_page(&anchor_); 1029 anchor_.set_next_page(&anchor_);
1030 anchor_.set_prev_page(&anchor_); 1030 anchor_.set_prev_page(&anchor_);
1031 accounting_stats_.Clear(); 1031 accounting_stats_.Clear();
1032 } 1032 }
1033 1033
1034
1035 void PagedSpace::AddMemory(Address start, intptr_t size) {
1036 accounting_stats_.ExpandSpace(static_cast<int>(size));
1037 Free(start, static_cast<int>(size));
1038 }
1039
1040
1041 void PagedSpace::RefillFreeList() { 1034 void PagedSpace::RefillFreeList() {
1042 MarkCompactCollector* collector = heap()->mark_compact_collector(); 1035 // Any PagedSpace might invoke RefillFreeList. We filter all but our old
1043 FreeList* free_list = nullptr; 1036 // generation spaces out.
1044 if (this == heap()->old_space()) { 1037 if (identity() != OLD_SPACE && identity() != CODE_SPACE &&
1045 free_list = collector->free_list_old_space().get(); 1038 identity() != MAP_SPACE) {
1046 } else if (this == heap()->code_space()) {
1047 free_list = collector->free_list_code_space().get();
1048 } else if (this == heap()->map_space()) {
1049 free_list = collector->free_list_map_space().get();
1050 } else {
1051 // Any PagedSpace might invoke RefillFreeList. We filter all but our old
1052 // generation spaces out.
1053 return; 1039 return;
1054 } 1040 }
1055 DCHECK(free_list != nullptr); 1041 MarkCompactCollector* collector = heap()->mark_compact_collector();
1056 intptr_t added = free_list_.Concatenate(free_list); 1042 List<Page*>* swept_pages = collector->swept_pages(identity());
1043 intptr_t added = 0;
1044 {
1045 base::LockGuard<base::Mutex> guard(collector->swept_pages_mutex());
1046 for (int i = swept_pages->length() - 1; i >= 0; --i) {
1047 Page* p = (*swept_pages)[i];
1048 // Only during compaction pages can actually change ownership. This is
1049 // safe because there exists no other competing action on the page links
1050 // during compaction.
1051 if (is_local() && (p->owner() != this)) {
1052 if (added > kCompactionMemoryWanted) break;
1053 base::LockGuard<base::Mutex> guard(
1054 reinterpret_cast<PagedSpace*>(p->owner())->mutex());
1055 p->Unlink();
1056 p->set_owner(this);
1057 p->InsertAfter(anchor_.prev_page());
1058 }
1059 added += RelinkFreeListCategories(p);
1060 added += p->wasted_memory();
1061 swept_pages->Remove(i);
1062 }
1063 }
1057 accounting_stats_.IncreaseCapacity(added); 1064 accounting_stats_.IncreaseCapacity(added);
1058 } 1065 }
1059 1066
1060 1067 void PagedSpace::MergeCompactionSpace(CompactionSpace* other) {
1061 void CompactionSpace::RefillFreeList() {
1062 MarkCompactCollector* collector = heap()->mark_compact_collector();
1063 FreeList* free_list = nullptr;
1064 if (identity() == OLD_SPACE) {
1065 free_list = collector->free_list_old_space().get();
1066 } else if (identity() == CODE_SPACE) {
1067 free_list = collector->free_list_code_space().get();
1068 } else {
1069 // Compaction spaces only represent old or code space.
1070 UNREACHABLE();
1071 }
1072 DCHECK(free_list != nullptr);
1073 intptr_t refilled = 0;
1074 while (refilled < kCompactionMemoryWanted) {
1075 FreeSpace* node =
1076 free_list->TryRemoveMemory(kCompactionMemoryWanted - refilled);
1077 if (node == nullptr) return;
1078 refilled += node->size();
1079 AddMemory(node->address(), node->size());
1080 }
1081 }
1082
1083 void PagedSpace::MoveOverFreeMemory(PagedSpace* other) {
1084 DCHECK(identity() == other->identity()); 1068 DCHECK(identity() == other->identity());
1085 // Destroy the linear allocation space of {other}. This is needed to
1086 // (a) not waste the memory and
1087 // (b) keep the rest of the chunk in an iterable state (filler is needed).
1088 other->EmptyAllocationInfo();
1089
1090 // Move over the free list. Concatenate makes sure that the source free list
1091 // gets properly reset after moving over all nodes.
1092 intptr_t added = free_list_.Concatenate(other->free_list());
1093
1094 // Moved memory is not recorded as allocated memory, but rather increases and
1095 // decreases capacity of the corresponding spaces.
1096 other->accounting_stats_.DecreaseCapacity(added);
1097 accounting_stats_.IncreaseCapacity(added);
1098 }
1099
1100
1101 void PagedSpace::MergeCompactionSpace(CompactionSpace* other) {
1102 // Unmerged fields: 1069 // Unmerged fields:
1103 // area_size_ 1070 // area_size_
1104 // anchor_ 1071 // anchor_
1105 1072
1106 MoveOverFreeMemory(other); 1073 other->EmptyAllocationInfo();
1107 1074
1108 // Update and clear accounting statistics. 1075 // Update and clear accounting statistics.
1109 accounting_stats_.Merge(other->accounting_stats_); 1076 accounting_stats_.Merge(other->accounting_stats_);
1110 other->accounting_stats_.Clear(); 1077 other->accounting_stats_.Clear();
1111 1078
1112 // The linear allocation area of {other} should be destroyed now. 1079 // The linear allocation area of {other} should be destroyed now.
1113 DCHECK(other->top() == nullptr); 1080 DCHECK(other->top() == nullptr);
1114 DCHECK(other->limit() == nullptr); 1081 DCHECK(other->limit() == nullptr);
1115 1082
1116 AccountCommitted(other->CommittedMemory()); 1083 AccountCommitted(other->CommittedMemory());
1117 1084
1118 // Move over pages. 1085 // Move over pages.
1119 PageIterator it(other); 1086 PageIterator it(other);
1120 Page* p = nullptr; 1087 Page* p = nullptr;
1121 while (it.has_next()) { 1088 while (it.has_next()) {
1122 p = it.next(); 1089 p = it.next();
1090
1091 // Relinking requires the category to be unlinked.
1092 other->UnlinkFreeListCategories(p);
1093
1123 p->Unlink(); 1094 p->Unlink();
1124 p->set_owner(this); 1095 p->set_owner(this);
1125 p->InsertAfter(anchor_.prev_page()); 1096 p->InsertAfter(anchor_.prev_page());
1097 RelinkFreeListCategories(p);
1126 } 1098 }
1127 } 1099 }
1128 1100
1129 1101
1130 size_t PagedSpace::CommittedPhysicalMemory() { 1102 size_t PagedSpace::CommittedPhysicalMemory() {
1131 if (!base::VirtualMemory::HasLazyCommits()) return CommittedMemory(); 1103 if (!base::VirtualMemory::HasLazyCommits()) return CommittedMemory();
1132 MemoryChunk::UpdateHighWaterMark(allocation_info_.top()); 1104 MemoryChunk::UpdateHighWaterMark(allocation_info_.top());
1133 size_t size = 0; 1105 size_t size = 0;
1134 PageIterator it(this); 1106 PageIterator it(this);
1135 while (it.has_next()) { 1107 while (it.has_next()) {
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1222 Page* page = page_iterator.next(); 1194 Page* page = page_iterator.next();
1223 page->ResetFreeListStatistics(); 1195 page->ResetFreeListStatistics();
1224 } 1196 }
1225 } 1197 }
1226 1198
1227 1199
1228 void PagedSpace::IncreaseCapacity(int size) { 1200 void PagedSpace::IncreaseCapacity(int size) {
1229 accounting_stats_.ExpandSpace(size); 1201 accounting_stats_.ExpandSpace(size);
1230 } 1202 }
1231 1203
1204 void PagedSpace::ReleasePage(Page* page) {
1205 DCHECK_EQ(page->LiveBytes(), 0);
1206 DCHECK_EQ(AreaSize(), page->area_size());
1207 DCHECK_EQ(page->owner(), this);
1232 1208
1233 void PagedSpace::ReleasePage(Page* page, bool evict_free_list_items) { 1209 free_list_.EvictFreeListItems(page);
1234 DCHECK(page->LiveBytes() == 0);
1235 DCHECK(AreaSize() == page->area_size());
1236
1237 if (evict_free_list_items) {
1238 intptr_t size = free_list_.EvictFreeListItems(page);
1239 accounting_stats_.AllocateBytes(size);
1240 DCHECK_EQ(AreaSize(), static_cast<int>(size));
1241 }
1242
1243 DCHECK(!free_list_.ContainsPageFreeListItems(page)); 1210 DCHECK(!free_list_.ContainsPageFreeListItems(page));
1244 1211
1245 if (Page::FromAllocationTop(allocation_info_.top()) == page) { 1212 if (Page::FromAllocationTop(allocation_info_.top()) == page) {
1246 allocation_info_.Reset(nullptr, nullptr); 1213 allocation_info_.Reset(nullptr, nullptr);
1247 } 1214 }
1248 1215
1249 // If page is still in a list, unlink it from that list. 1216 // If page is still in a list, unlink it from that list.
1250 if (page->next_chunk() != NULL) { 1217 if (page->next_chunk() != NULL) {
1251 DCHECK(page->prev_chunk() != NULL); 1218 DCHECK(page->prev_chunk() != NULL);
1252 page->Unlink(); 1219 page->Unlink();
1253 } 1220 }
1254 1221
1255 AccountUncommitted(static_cast<intptr_t>(page->size())); 1222 AccountUncommitted(static_cast<intptr_t>(page->size()));
1256 heap()->QueueMemoryChunkForFree(page); 1223 heap()->QueueMemoryChunkForFree(page);
1257 1224
1258 DCHECK(Capacity() > 0); 1225 DCHECK(Capacity() > 0);
1259 accounting_stats_.ShrinkSpace(AreaSize()); 1226 accounting_stats_.ShrinkSpace(AreaSize());
1260 } 1227 }
1261 1228
1262
1263 #ifdef DEBUG 1229 #ifdef DEBUG
1264 void PagedSpace::Print() {} 1230 void PagedSpace::Print() {}
1265 #endif 1231 #endif
1266 1232
1267 #ifdef VERIFY_HEAP 1233 #ifdef VERIFY_HEAP
1268 void PagedSpace::Verify(ObjectVisitor* visitor) { 1234 void PagedSpace::Verify(ObjectVisitor* visitor) {
1269 bool allocation_pointer_found_in_space = 1235 bool allocation_pointer_found_in_space =
1270 (allocation_info_.top() == allocation_info_.limit()); 1236 (allocation_info_.top() == allocation_info_.limit());
1271 PageIterator page_iterator(this); 1237 PageIterator page_iterator(this);
1272 while (page_iterator.has_next()) { 1238 while (page_iterator.has_next()) {
(...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after
2158 if (from_space_.is_committed()) { 2124 if (from_space_.is_committed()) {
2159 size += from_space_.CommittedPhysicalMemory(); 2125 size += from_space_.CommittedPhysicalMemory();
2160 } 2126 }
2161 return size; 2127 return size;
2162 } 2128 }
2163 2129
2164 2130
2165 // ----------------------------------------------------------------------------- 2131 // -----------------------------------------------------------------------------
2166 // Free lists for old object spaces implementation 2132 // Free lists for old object spaces implementation
2167 2133
2168 intptr_t FreeListCategory::Concatenate(FreeListCategory* category) {
2169 intptr_t free_bytes = 0;
2170 if (category->top() != NULL) {
2171 DCHECK(category->end_ != NULL);
2172 free_bytes = category->available();
2173 if (end_ == NULL) {
2174 end_ = category->end();
2175 } else {
2176 category->end()->set_next(top());
2177 }
2178 set_top(category->top());
2179 available_ += category->available();
2180 category->Reset();
2181 }
2182 return free_bytes;
2183 }
2184
2185 2134
2186 void FreeListCategory::Reset() { 2135 void FreeListCategory::Reset() {
2187 set_top(nullptr); 2136 set_top(nullptr);
2188 set_end(nullptr); 2137 set_prev(nullptr);
2138 set_next(nullptr);
2189 available_ = 0; 2139 available_ = 0;
2190 } 2140 }
2191 2141
2142 FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) {
2143 DCHECK(page()->CanAllocate());
2192 2144
2193 intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) {
2194 intptr_t sum = 0;
2195 FreeSpace* prev_node = nullptr;
2196 for (FreeSpace* cur_node = top(); cur_node != nullptr;
2197 cur_node = cur_node->next()) {
2198 Page* page_for_node = Page::FromAddress(cur_node->address());
2199 if (page_for_node == p) {
2200 // FreeSpace node on eviction page found, unlink it.
2201 int size = cur_node->size();
2202 sum += size;
2203 DCHECK((prev_node != nullptr) || (top() == cur_node));
2204 if (cur_node == top()) {
2205 set_top(cur_node->next());
2206 }
2207 if (cur_node == end()) {
2208 set_end(prev_node);
2209 }
2210 if (prev_node != nullptr) {
2211 prev_node->set_next(cur_node->next());
2212 }
2213 continue;
2214 }
2215 prev_node = cur_node;
2216 }
2217 p->add_available_in_free_list(-sum);
2218 available_ -= sum;
2219 return sum;
2220 }
2221
2222
2223 bool FreeListCategory::ContainsPageFreeListItemsInList(Page* p) {
2224 FreeSpace* node = top();
2225 while (node != NULL) {
2226 if (Page::FromAddress(node->address()) == p) return true;
2227 node = node->next();
2228 }
2229 return false;
2230 }
2231
2232
2233 FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) {
2234 FreeSpace* node = top(); 2145 FreeSpace* node = top();
2235 if (node == nullptr) return nullptr; 2146 if (node == nullptr) return nullptr;
2236 2147 set_top(node->next());
2237 Page* page = Page::FromAddress(node->address()); 2148 *node_size = node->Size();
2238 while ((node != nullptr) && !page->CanAllocate()) { 2149 available_ -= *node_size;
2239 available_ -= node->size();
2240 page->add_available_in_free_list(-(node->Size()));
2241 node = node->next();
2242 }
2243
2244 if (node != nullptr) {
2245 set_top(node->next());
2246 *node_size = node->Size();
2247 available_ -= *node_size;
2248 } else {
2249 set_top(nullptr);
2250 }
2251
2252 if (top() == nullptr) {
2253 set_end(nullptr);
2254 }
2255
2256 return node; 2150 return node;
2257 } 2151 }
2258 2152
2153 FreeSpace* FreeListCategory::TryPickNodeFromList(int minimum_size,
2154 int* node_size) {
2155 DCHECK(page()->CanAllocate());
2259 2156
2260 FreeSpace* FreeListCategory::PickNodeFromList(int size_in_bytes,
2261 int* node_size) {
2262 FreeSpace* node = PickNodeFromList(node_size); 2157 FreeSpace* node = PickNodeFromList(node_size);
2263 if ((node != nullptr) && (*node_size < size_in_bytes)) { 2158 if ((node != nullptr) && (*node_size < minimum_size)) {
2264 Free(node, *node_size); 2159 Free(node, *node_size, kLinkCategory);
2265 *node_size = 0; 2160 *node_size = 0;
2266 return nullptr; 2161 return nullptr;
2267 } 2162 }
2268 return node; 2163 return node;
2269 } 2164 }
2270 2165
2166 FreeSpace* FreeListCategory::SearchForNodeInList(int minimum_size,
2167 int* node_size) {
2168 DCHECK(page()->CanAllocate());
2271 2169
2272 FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes,
2273 int* node_size) {
2274 FreeSpace* prev_non_evac_node = nullptr; 2170 FreeSpace* prev_non_evac_node = nullptr;
2275 for (FreeSpace* cur_node = top(); cur_node != nullptr; 2171 for (FreeSpace* cur_node = top(); cur_node != nullptr;
2276 cur_node = cur_node->next()) { 2172 cur_node = cur_node->next()) {
2277 int size = cur_node->size(); 2173 int size = cur_node->size();
2278 Page* page_for_node = Page::FromAddress(cur_node->address()); 2174 if (size >= minimum_size) {
2279
2280 if ((size >= size_in_bytes) || !page_for_node->CanAllocate()) {
2281 // The node is either large enough or contained in an evacuation
2282 // candidate. In both cases we need to unlink it from the list.
2283 available_ -= size; 2175 available_ -= size;
2284 if (cur_node == top()) { 2176 if (cur_node == top()) {
2285 set_top(cur_node->next()); 2177 set_top(cur_node->next());
2286 } 2178 }
2287 if (cur_node == end()) {
2288 set_end(prev_non_evac_node);
2289 }
2290 if (prev_non_evac_node != nullptr) { 2179 if (prev_non_evac_node != nullptr) {
2291 prev_non_evac_node->set_next(cur_node->next()); 2180 prev_non_evac_node->set_next(cur_node->next());
2292 } 2181 }
2293 // For evacuation candidates we continue.
2294 if (!page_for_node->CanAllocate()) {
2295 page_for_node->add_available_in_free_list(-size);
2296 continue;
2297 }
2298 // Otherwise we have a large enough node and can return.
2299 *node_size = size; 2182 *node_size = size;
2300 return cur_node; 2183 return cur_node;
2301 } 2184 }
2302 2185
2303 prev_non_evac_node = cur_node; 2186 prev_non_evac_node = cur_node;
2304 } 2187 }
2305 return nullptr; 2188 return nullptr;
2306 } 2189 }
2307 2190
2191 bool FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes,
2192 FreeMode mode) {
2193 if (!page()->CanAllocate()) return false;
2308 2194
2309 void FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes) {
2310 free_space->set_next(top()); 2195 free_space->set_next(top());
2311 set_top(free_space); 2196 set_top(free_space);
2312 if (end_ == NULL) { 2197 available_ += size_in_bytes;
2313 end_ = free_space; 2198 if ((mode == kLinkCategory) && (prev() == nullptr) && (next() == nullptr)) {
2199 owner()->AddCategory(this);
2314 } 2200 }
2315 available_ += size_in_bytes; 2201 return true;
2316 } 2202 }
2317 2203
2318 2204
2319 void FreeListCategory::RepairFreeList(Heap* heap) { 2205 void FreeListCategory::RepairFreeList(Heap* heap) {
2320 FreeSpace* n = top(); 2206 FreeSpace* n = top();
2321 while (n != NULL) { 2207 while (n != NULL) {
2322 Map** map_location = reinterpret_cast<Map**>(n->address()); 2208 Map** map_location = reinterpret_cast<Map**>(n->address());
2323 if (*map_location == NULL) { 2209 if (*map_location == NULL) {
2324 *map_location = heap->free_space_map(); 2210 *map_location = heap->free_space_map();
2325 } else { 2211 } else {
2326 DCHECK(*map_location == heap->free_space_map()); 2212 DCHECK(*map_location == heap->free_space_map());
2327 } 2213 }
2328 n = n->next(); 2214 n = n->next();
2329 } 2215 }
2330 } 2216 }
2331 2217
2218 void FreeListCategory::Relink() {
2219 DCHECK(!is_linked());
2220 owner()->AddCategory(this);
2221 }
2222
2223 void FreeListCategory::Invalidate() {
2224 page()->add_available_in_free_list(-available());
2225 Reset();
2226 type_ = kInvalidCategory;
2227 }
2228
2332 FreeList::FreeList(PagedSpace* owner) : owner_(owner), wasted_bytes_(0) { 2229 FreeList::FreeList(PagedSpace* owner) : owner_(owner), wasted_bytes_(0) {
2333 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { 2230 for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
2334 category_[i].Initialize(this, static_cast<FreeListCategoryType>(i)); 2231 categories_[i] = nullptr;
2335 } 2232 }
2336 Reset(); 2233 Reset();
2337 } 2234 }
2338 2235
2339 2236
2340 intptr_t FreeList::Concatenate(FreeList* other) { 2237 void FreeList::Reset() {
2341 intptr_t usable_bytes = 0; 2238 ForAllFreeListCategories(
2342 intptr_t wasted_bytes = 0; 2239 [](FreeListCategory* category) { category->Reset(); });
2343
2344 // This is safe (not going to deadlock) since Concatenate operations
2345 // are never performed on the same free lists at the same time in
2346 // reverse order. Furthermore, we only lock if the PagedSpace containing
2347 // the free list is know to be globally available, i.e., not local.
2348 if (!owner()->is_local()) mutex_.Lock();
2349 if (!other->owner()->is_local()) other->mutex()->Lock();
2350
2351 wasted_bytes = other->wasted_bytes_;
2352 wasted_bytes_ += wasted_bytes;
2353 other->wasted_bytes_ = 0;
2354
2355 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { 2240 for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
2356 usable_bytes += category_[i].Concatenate( 2241 categories_[i] = nullptr;
2357 other->GetFreeListCategory(static_cast<FreeListCategoryType>(i)));
2358 }
2359
2360 if (!other->owner()->is_local()) other->mutex()->Unlock();
2361 if (!owner()->is_local()) mutex_.Unlock();
2362 return usable_bytes + wasted_bytes;
2363 }
2364
2365
2366 void FreeList::Reset() {
2367 for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
2368 category_[i].Reset();
2369 } 2242 }
2370 ResetStats(); 2243 ResetStats();
2371 } 2244 }
2372 2245
2373 2246 int FreeList::Free(Address start, int size_in_bytes, FreeMode mode) {
2374 int FreeList::Free(Address start, int size_in_bytes) {
2375 if (size_in_bytes == 0) return 0; 2247 if (size_in_bytes == 0) return 0;
2376 2248
2377 owner()->heap()->CreateFillerObjectAt(start, size_in_bytes, 2249 owner()->heap()->CreateFillerObjectAt(start, size_in_bytes,
2378 ClearRecordedSlots::kNo); 2250 ClearRecordedSlots::kNo);
2379 2251
2380 Page* page = Page::FromAddress(start); 2252 Page* page = Page::FromAddress(start);
2381 2253
2382 // Blocks have to be a minimum size to hold free list items. 2254 // Blocks have to be a minimum size to hold free list items.
2383 if (size_in_bytes < kMinBlockSize) { 2255 if (size_in_bytes < kMinBlockSize) {
2384 page->add_wasted_memory(size_in_bytes); 2256 page->add_wasted_memory(size_in_bytes);
2385 wasted_bytes_ += size_in_bytes; 2257 wasted_bytes_.Increment(size_in_bytes);
2386 return size_in_bytes; 2258 return size_in_bytes;
2387 } 2259 }
2388 2260
2389 FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start)); 2261 FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start));
2390 // Insert other blocks at the head of a free list of the appropriate 2262 // Insert other blocks at the head of a free list of the appropriate
2391 // magnitude. 2263 // magnitude.
2392 FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes); 2264 FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
2393 category_[type].Free(free_space, size_in_bytes); 2265 if (page->free_list_category(type)->Free(free_space, size_in_bytes, mode)) {
2394 page->add_available_in_free_list(size_in_bytes); 2266 page->add_available_in_free_list(size_in_bytes);
2395 2267 }
2396 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2397 return 0; 2268 return 0;
2398 } 2269 }
2399 2270
2271 FreeSpace* FreeList::FindNodeIn(FreeListCategoryType type, int* node_size) {
2272 FreeListCategoryIterator it(this, type);
2273 FreeSpace* node = nullptr;
2274 while (it.HasNext()) {
2275 FreeListCategory* current = it.Next();
2276 node = current->PickNodeFromList(node_size);
2277 if (node != nullptr) {
2278 Page::FromAddress(node->address())
2279 ->add_available_in_free_list(-(*node_size));
2280 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2281 return node;
2282 }
2283 }
2284 return node;
2285 }
2400 2286
2401 FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { 2287 FreeSpace* FreeList::TryFindNodeIn(FreeListCategoryType type, int* node_size,
2402 FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size); 2288 int minimum_size) {
2289 if (categories_[type] == nullptr) return nullptr;
2290 FreeSpace* node =
2291 categories_[type]->TryPickNodeFromList(minimum_size, node_size);
2403 if (node != nullptr) { 2292 if (node != nullptr) {
2404 Page::FromAddress(node->address()) 2293 Page::FromAddress(node->address())
2405 ->add_available_in_free_list(-(*node_size)); 2294 ->add_available_in_free_list(-(*node_size));
2406 DCHECK(IsVeryLong() || Available() == SumFreeLists()); 2295 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2407 } 2296 }
2408 return node; 2297 return node;
2409 } 2298 }
2410 2299
2300 FreeSpace* FreeList::SearchForNodeInList(FreeListCategoryType type,
2301 int* node_size, int minimum_size) {
2302 FreeListCategoryIterator it(this, type);
2303 FreeSpace* node = nullptr;
2304 while (it.HasNext()) {
2305 FreeListCategory* current = it.Next();
2306 node = current->SearchForNodeInList(minimum_size, node_size);
2307 if (node != nullptr) {
2308 Page::FromAddress(node->address())
2309 ->add_available_in_free_list(-(*node_size));
2310 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2311 return node;
2312 }
2313 }
2314 return node;
2315 }
2411 2316
2412 FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { 2317 FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
2413 FreeSpace* node = nullptr; 2318 FreeSpace* node = nullptr;
2414 Page* page = nullptr; 2319 Page* page = nullptr;
2415 2320
2416 // First try the allocation fast path: try to allocate the minimum element 2321 // First try the allocation fast path: try to allocate the minimum element
2417 // size of a free list category. This operation is constant time. 2322 // size of a free list category. This operation is constant time.
2418 FreeListCategoryType type = 2323 FreeListCategoryType type =
2419 SelectFastAllocationFreeListCategoryType(size_in_bytes); 2324 SelectFastAllocationFreeListCategoryType(size_in_bytes);
2420 for (int i = type; i < kHuge; i++) { 2325 for (int i = type; i < kHuge; i++) {
2421 node = FindNodeIn(static_cast<FreeListCategoryType>(i), node_size); 2326 node = FindNodeIn(static_cast<FreeListCategoryType>(i), node_size);
2422 if (node != nullptr) return node; 2327 if (node != nullptr) return node;
2423 } 2328 }
2424 2329
2425 // Next search the huge list for free list nodes. This takes linear time in 2330 // Next search the huge list for free list nodes. This takes linear time in
2426 // the number of huge elements. 2331 // the number of huge elements.
2427 node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size); 2332 node = SearchForNodeInList(kHuge, node_size, size_in_bytes);
2428 if (node != nullptr) { 2333 if (node != nullptr) {
2429 page = Page::FromAddress(node->address());
2430 page->add_available_in_free_list(-(*node_size));
2431 DCHECK(IsVeryLong() || Available() == SumFreeLists()); 2334 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2432 return node; 2335 return node;
2433 } 2336 }
2434 2337
2435 // We need a huge block of memory, but we didn't find anything in the huge 2338 // We need a huge block of memory, but we didn't find anything in the huge
2436 // list. 2339 // list.
2437 if (type == kHuge) return nullptr; 2340 if (type == kHuge) return nullptr;
2438 2341
2439 // Now search the best fitting free list for a node that has at least the 2342 // Now search the best fitting free list for a node that has at least the
2440 // requested size. 2343 // requested size.
2441 type = SelectFreeListCategoryType(size_in_bytes); 2344 type = SelectFreeListCategoryType(size_in_bytes);
2442 node = category_[type].PickNodeFromList(size_in_bytes, node_size); 2345 node = TryFindNodeIn(type, node_size, size_in_bytes);
2443 if (node != nullptr) { 2346 if (node != nullptr) {
2444 DCHECK(size_in_bytes <= *node_size); 2347 DCHECK(size_in_bytes <= *node_size);
2445 page = Page::FromAddress(node->address()); 2348 page = Page::FromAddress(node->address());
2446 page->add_available_in_free_list(-(*node_size)); 2349 page->add_available_in_free_list(-(*node_size));
2447 } 2350 }
2448 2351
2449 DCHECK(IsVeryLong() || Available() == SumFreeLists()); 2352 DCHECK(IsVeryLong() || Available() == SumFreeLists());
2450 return node; 2353 return node;
2451 } 2354 }
2452 2355
2453
2454 FreeSpace* FreeList::TryRemoveMemory(intptr_t hint_size_in_bytes) {
2455 hint_size_in_bytes = RoundDown(hint_size_in_bytes, kPointerSize);
2456 base::LockGuard<base::Mutex> guard(&mutex_);
2457 FreeSpace* node = nullptr;
2458 int node_size = 0;
2459 // Try to find a node that fits exactly.
2460 node = FindNodeFor(static_cast<int>(hint_size_in_bytes), &node_size);
2461 // If no node could be found get as much memory as possible.
2462 if (node == nullptr) node = FindNodeIn(kHuge, &node_size);
2463 if (node == nullptr) node = FindNodeIn(kLarge, &node_size);
2464 if (node != nullptr) {
2465 // We round up the size to (kMinBlockSize + kPointerSize) to (a) have a
2466 // size larger then the minimum size required for FreeSpace, and (b) to get
2467 // a block that can actually be freed into some FreeList later on.
2468 if (hint_size_in_bytes <= kMinBlockSize) {
2469 hint_size_in_bytes = kMinBlockSize + kPointerSize;
2470 }
2471 // Give back left overs that were not required by {size_in_bytes}.
2472 intptr_t left_over = node_size - hint_size_in_bytes;
2473
2474 // Do not bother to return anything below {kMinBlockSize} as it would be
2475 // immediately discarded anyways.
2476 if (left_over > kMinBlockSize) {
2477 Free(node->address() + hint_size_in_bytes, static_cast<int>(left_over));
2478 node->set_size(static_cast<int>(hint_size_in_bytes));
2479 }
2480 }
2481 return node;
2482 }
2483
2484
2485 // Allocation on the old space free list. If it succeeds then a new linear 2356 // Allocation on the old space free list. If it succeeds then a new linear
2486 // allocation space has been set up with the top and limit of the space. If 2357 // allocation space has been set up with the top and limit of the space. If
2487 // the allocation fails then NULL is returned, and the caller can perform a GC 2358 // the allocation fails then NULL is returned, and the caller can perform a GC
2488 // or allocate a new page before retrying. 2359 // or allocate a new page before retrying.
2489 HeapObject* FreeList::Allocate(int size_in_bytes) { 2360 HeapObject* FreeList::Allocate(int size_in_bytes) {
2490 DCHECK(0 < size_in_bytes); 2361 DCHECK(0 < size_in_bytes);
2491 DCHECK(size_in_bytes <= kMaxBlockSize); 2362 DCHECK(size_in_bytes <= kMaxBlockSize);
2492 DCHECK(IsAligned(size_in_bytes, kPointerSize)); 2363 DCHECK(IsAligned(size_in_bytes, kPointerSize));
2493 // Don't free list allocate if there is linear space available. 2364 // Don't free list allocate if there is linear space available.
2494 DCHECK(owner_->limit() - owner_->top() < size_in_bytes); 2365 DCHECK(owner_->limit() - owner_->top() < size_in_bytes);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
2548 } else if (bytes_left > 0) { 2419 } else if (bytes_left > 0) {
2549 // Normally we give the rest of the node to the allocator as its new 2420 // Normally we give the rest of the node to the allocator as its new
2550 // linear allocation area. 2421 // linear allocation area.
2551 owner_->SetTopAndLimit(new_node->address() + size_in_bytes, 2422 owner_->SetTopAndLimit(new_node->address() + size_in_bytes,
2552 new_node->address() + new_node_size); 2423 new_node->address() + new_node_size);
2553 } 2424 }
2554 2425
2555 return new_node; 2426 return new_node;
2556 } 2427 }
2557 2428
2558 2429 intptr_t FreeList::EvictFreeListItems(Page* page) {
2559 intptr_t FreeList::EvictFreeListItems(Page* p) { 2430 intptr_t sum = 0;
2560 intptr_t sum = category_[kHuge].EvictFreeListItemsInList(p); 2431 page->ForAllFreeListCategories(
2561 if (sum < p->area_size()) { 2432 [this, &sum, page](FreeListCategory* category) {
2562 for (int i = kFirstCategory; i <= kLarge; i++) { 2433 DCHECK_EQ(this, category->owner());
2563 sum += category_[i].EvictFreeListItemsInList(p); 2434 sum += category->available();
2564 } 2435 RemoveCategory(category);
2565 } 2436 category->Invalidate();
2437 });
2566 return sum; 2438 return sum;
2567 } 2439 }
2568 2440
2441 bool FreeList::ContainsPageFreeListItems(Page* page) {
2442 bool contained = false;
2443 page->ForAllFreeListCategories(
2444 [this, &contained](FreeListCategory* category) {
2445 if (category->owner() == this && category->is_linked()) {
2446 contained = true;
2447 }
2448 });
2449 return contained;
2450 }
2569 2451
2570 bool FreeList::ContainsPageFreeListItems(Page* p) { 2452 void FreeList::RepairLists(Heap* heap) {
2571 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { 2453 ForAllFreeListCategories(
2572 if (category_[i].EvictFreeListItemsInList(p)) { 2454 [heap](FreeListCategory* category) { category->RepairFreeList(heap); });
2573 return true; 2455 }
2574 } 2456
2457 bool FreeList::AddCategory(FreeListCategory* category) {
2458 FreeListCategoryType type = category->type_;
2459 FreeListCategory* top = categories_[type];
2460
2461 if (category->is_empty()) return false;
2462 if (top == category) return false;
2463
2464 // Common double-linked list insertion.
2465 if (top != nullptr) {
2466 top->set_prev(category);
2575 } 2467 }
2576 return false; 2468 category->set_next(top);
2469 categories_[type] = category;
2470 return true;
2471 }
2472
2473 void FreeList::RemoveCategory(FreeListCategory* category) {
2474 FreeListCategoryType type = category->type_;
2475 FreeListCategory* top = categories_[type];
2476
2477 // Common double-linked list removal.
2478 if (top == category) {
2479 categories_[type] = category->next();
2480 }
2481 if (category->prev() != nullptr) {
2482 category->prev()->set_next(category->next());
2483 }
2484 if (category->next() != nullptr) {
2485 category->next()->set_prev(category->prev());
2486 }
2487 category->set_next(nullptr);
2488 category->set_prev(nullptr);
2489 }
2490
2491 void FreeList::PrintCategories(FreeListCategoryType type) {
2492 FreeListCategoryIterator it(this, type);
2493 PrintF("FreeList[%p, top=%p, %d] ", this, categories_[type], type);
2494 while (it.HasNext()) {
2495 FreeListCategory* current = it.Next();
2496 PrintF("%p -> ", current);
2497 }
2498 PrintF("null\n");
2577 } 2499 }
2578 2500
2579 2501
2580 void FreeList::RepairLists(Heap* heap) {
2581 for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
2582 category_[i].RepairFreeList(heap);
2583 }
2584 }
2585
2586
2587 #ifdef DEBUG 2502 #ifdef DEBUG
2588 intptr_t FreeListCategory::SumFreeList() { 2503 intptr_t FreeListCategory::SumFreeList() {
2589 intptr_t sum = 0; 2504 intptr_t sum = 0;
2590 FreeSpace* cur = top(); 2505 FreeSpace* cur = top();
2591 while (cur != NULL) { 2506 while (cur != NULL) {
2592 DCHECK(cur->map() == cur->GetHeap()->root(Heap::kFreeSpaceMapRootIndex)); 2507 DCHECK(cur->map() == cur->GetHeap()->root(Heap::kFreeSpaceMapRootIndex));
2593 sum += cur->nobarrier_size(); 2508 sum += cur->nobarrier_size();
2594 cur = cur->next(); 2509 cur = cur->next();
2595 } 2510 }
2596 return sum; 2511 return sum;
2597 } 2512 }
2598 2513
2599
2600 int FreeListCategory::FreeListLength() { 2514 int FreeListCategory::FreeListLength() {
2601 int length = 0; 2515 int length = 0;
2602 FreeSpace* cur = top(); 2516 FreeSpace* cur = top();
2603 while (cur != NULL) { 2517 while (cur != NULL) {
2604 length++; 2518 length++;
2605 cur = cur->next(); 2519 cur = cur->next();
2606 if (length == kVeryLongFreeList) return length; 2520 if (length == kVeryLongFreeList) return length;
2607 } 2521 }
2608 return length; 2522 return length;
2609 } 2523 }
2610 2524
2611
2612 bool FreeListCategory::IsVeryLong() {
2613 return FreeListLength() == kVeryLongFreeList;
2614 }
2615
2616
2617 bool FreeList::IsVeryLong() { 2525 bool FreeList::IsVeryLong() {
2526 int len = 0;
2618 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { 2527 for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
2619 if (category_[i].IsVeryLong()) { 2528 FreeListCategoryIterator it(this, static_cast<FreeListCategoryType>(i));
2620 return true; 2529 while (it.HasNext()) {
2530 len += it.Next()->FreeListLength();
2531 if (len >= FreeListCategory::kVeryLongFreeList) return true;
2621 } 2532 }
2622 } 2533 }
2623 return false; 2534 return false;
2624 } 2535 }
2625 2536
2626 2537
2627 // This can take a very long time because it is linear in the number of entries 2538 // This can take a very long time because it is linear in the number of entries
2628 // on the free list, so it should not be called if FreeListLength returns 2539 // on the free list, so it should not be called if FreeListLength returns
2629 // kVeryLongFreeList. 2540 // kVeryLongFreeList.
2630 intptr_t FreeList::SumFreeLists() { 2541 intptr_t FreeList::SumFreeLists() {
2631 intptr_t sum = 0; 2542 intptr_t sum = 0;
2632 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { 2543 ForAllFreeListCategories(
2633 sum += category_[i].SumFreeList(); 2544 [&sum](FreeListCategory* category) { sum += category->SumFreeList(); });
2634 }
2635 return sum; 2545 return sum;
2636 } 2546 }
2637 #endif 2547 #endif
2638 2548
2639 2549
2640 // ----------------------------------------------------------------------------- 2550 // -----------------------------------------------------------------------------
2641 // OldSpace implementation 2551 // OldSpace implementation
2642 2552
2643 void PagedSpace::PrepareForMarkCompact() { 2553 void PagedSpace::PrepareForMarkCompact() {
2644 // We don't have a linear allocation area while sweeping. It will be restored 2554 // We don't have a linear allocation area while sweeping. It will be restored
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
3242 object->ShortPrint(); 3152 object->ShortPrint();
3243 PrintF("\n"); 3153 PrintF("\n");
3244 } 3154 }
3245 printf(" --------------------------------------\n"); 3155 printf(" --------------------------------------\n");
3246 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); 3156 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes());
3247 } 3157 }
3248 3158
3249 #endif // DEBUG 3159 #endif // DEBUG
3250 } // namespace internal 3160 } // namespace internal
3251 } // namespace v8 3161 } // namespace v8
OLDNEW
« src/heap/spaces.h ('K') | « src/heap/spaces.h ('k') | src/heap/spaces-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698