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

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