| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |