| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 | 389 |
| 390 void Page::InitializeAsAnchor(PagedSpace* owner) { | 390 void Page::InitializeAsAnchor(PagedSpace* owner) { |
| 391 set_owner(owner); | 391 set_owner(owner); |
| 392 set_prev_page(this); | 392 set_prev_page(this); |
| 393 set_next_page(this); | 393 set_next_page(this); |
| 394 } | 394 } |
| 395 | 395 |
| 396 | 396 |
| 397 NewSpacePage* NewSpacePage::Initialize(Heap* heap, | 397 NewSpacePage* NewSpacePage::Initialize(Heap* heap, |
| 398 Address start, | 398 Address start, |
| 399 SemiSpaceId semispace_id) { | 399 SemiSpace* semi_space) { |
| 400 MemoryChunk* chunk = MemoryChunk::Initialize(heap, | 400 MemoryChunk* chunk = MemoryChunk::Initialize(heap, |
| 401 start, | 401 start, |
| 402 Page::kPageSize, | 402 Page::kPageSize, |
| 403 NOT_EXECUTABLE, | 403 NOT_EXECUTABLE, |
| 404 heap->new_space()); | 404 semi_space); |
| 405 chunk->set_next_chunk(NULL); | 405 chunk->set_next_chunk(NULL); |
| 406 chunk->set_prev_chunk(NULL); | 406 chunk->set_prev_chunk(NULL); |
| 407 chunk->initialize_scan_on_scavenge(true); | 407 chunk->initialize_scan_on_scavenge(true); |
| 408 bool in_to_space = (semispace_id != kFromSpace); | 408 bool in_to_space = (semi_space->id() != kFromSpace); |
| 409 chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE | 409 chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE |
| 410 : MemoryChunk::IN_FROM_SPACE); | 410 : MemoryChunk::IN_FROM_SPACE); |
| 411 ASSERT(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE | 411 ASSERT(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE |
| 412 : MemoryChunk::IN_TO_SPACE)); | 412 : MemoryChunk::IN_TO_SPACE)); |
| 413 heap->incremental_marking()->SetNewSpacePageFlags(chunk); | 413 heap->incremental_marking()->SetNewSpacePageFlags(chunk); |
| 414 return static_cast<NewSpacePage*>(chunk); | 414 return static_cast<NewSpacePage*>(chunk); |
| 415 } | 415 } |
| 416 | 416 |
| 417 | 417 |
| 418 void NewSpacePage::InitializeAsAnchor(SemiSpace* semi_space) { |
| 419 set_owner(semi_space); |
| 420 set_next_chunk(this); |
| 421 set_prev_chunk(this); |
| 422 } |
| 423 |
| 424 |
| 418 MemoryChunk* MemoryChunk::Initialize(Heap* heap, | 425 MemoryChunk* MemoryChunk::Initialize(Heap* heap, |
| 419 Address base, | 426 Address base, |
| 420 size_t size, | 427 size_t size, |
| 421 Executability executable, | 428 Executability executable, |
| 422 Space* owner) { | 429 Space* owner) { |
| 423 MemoryChunk* chunk = FromAddress(base); | 430 MemoryChunk* chunk = FromAddress(base); |
| 424 | 431 |
| 425 ASSERT(base == chunk->address()); | 432 ASSERT(base == chunk->address()); |
| 426 | 433 |
| 427 chunk->heap_ = heap; | 434 chunk->heap_ = heap; |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 heap()->isolate()->memory_allocator()->Unprotect(ToSpaceLow(), Capacity(), | 939 heap()->isolate()->memory_allocator()->Unprotect(ToSpaceLow(), Capacity(), |
| 933 to_space_.executable()); | 940 to_space_.executable()); |
| 934 heap()->isolate()->memory_allocator()->Unprotect(FromSpaceLow(), Capacity(), | 941 heap()->isolate()->memory_allocator()->Unprotect(FromSpaceLow(), Capacity(), |
| 935 from_space_.executable()); | 942 from_space_.executable()); |
| 936 } | 943 } |
| 937 | 944 |
| 938 #endif | 945 #endif |
| 939 | 946 |
| 940 | 947 |
| 941 void NewSpace::Flip() { | 948 void NewSpace::Flip() { |
| 942 SemiSpace tmp = from_space_; | 949 SemiSpace::Swap(&from_space_, &to_space_); |
| 943 from_space_ = to_space_; | |
| 944 to_space_ = tmp; | |
| 945 | |
| 946 // Copy GC flags from old active space (from-space) to new (to-space). | |
| 947 intptr_t flags = from_space_.current_page()->GetFlags(); | |
| 948 to_space_.Flip(flags, NewSpacePage::kCopyOnFlipFlagsMask); | |
| 949 | |
| 950 from_space_.Flip(0, 0); | |
| 951 } | 950 } |
| 952 | 951 |
| 953 | 952 |
| 954 void NewSpace::Grow() { | 953 void NewSpace::Grow() { |
| 955 ASSERT(Capacity() < MaximumCapacity()); | 954 ASSERT(Capacity() < MaximumCapacity()); |
| 956 if (to_space_.Grow()) { | 955 if (to_space_.Grow()) { |
| 957 // Only grow from space if we managed to grow to space. | 956 // Only grow from space if we managed to grow to space. |
| 958 if (!from_space_.Grow()) { | 957 if (!from_space_.Grow()) { |
| 959 // If we managed to grow to space but couldn't grow from space, | 958 // If we managed to grow to space but couldn't grow from space, |
| 960 // attempt to shrink to space. | 959 // attempt to shrink to space. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 986 V8::FatalProcessOutOfMemory("Failed to shrink new space."); | 985 V8::FatalProcessOutOfMemory("Failed to shrink new space."); |
| 987 } | 986 } |
| 988 } | 987 } |
| 989 } | 988 } |
| 990 allocation_info_.limit = to_space_.high(); | 989 allocation_info_.limit = to_space_.high(); |
| 991 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); | 990 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
| 992 } | 991 } |
| 993 | 992 |
| 994 | 993 |
| 995 void NewSpace::ResetAllocationInfo() { | 994 void NewSpace::ResetAllocationInfo() { |
| 996 allocation_info_.top = to_space_.low(); | 995 to_space_.Reset(); |
| 996 allocation_info_.top = to_space_.page_low(); |
| 997 allocation_info_.limit = to_space_.high(); | 997 allocation_info_.limit = to_space_.high(); |
| 998 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); | 998 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
| 999 } | 999 } |
| 1000 | 1000 |
| 1001 | 1001 |
| 1002 #ifdef DEBUG | 1002 #ifdef DEBUG |
| 1003 // We do not use the SemispaceIterator because verification doesn't assume | 1003 // We do not use the SemispaceIterator because verification doesn't assume |
| 1004 // that it works (it depends on the invariants we are checking). | 1004 // that it works (it depends on the invariants we are checking). |
| 1005 void NewSpace::Verify() { | 1005 void NewSpace::Verify() { |
| 1006 // The allocation pointer should be in the space or at the very end. | 1006 // The allocation pointer should be in the space or at the very end. |
| 1007 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); | 1007 ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
| 1008 | 1008 |
| 1009 // There should be objects packed in from the low address up to the | 1009 // There should be objects packed in from the low address up to the |
| 1010 // allocation pointer. | 1010 // allocation pointer. |
| 1011 Address current = to_space_.low(); | 1011 Address current = to_space_.low(); |
| 1012 while (current < top()) { | 1012 while (current < top()) { |
| 1013 HeapObject* object = HeapObject::FromAddress(current); | 1013 HeapObject* object = HeapObject::FromAddress(current); |
| 1014 | 1014 |
| 1015 // The first word should be a map, and we expect all map pointers to | 1015 // The first word should be a map, and we expect all map pointers to |
| 1016 // be in map space. | 1016 // be in map space. |
| 1017 Map* map = object->map(); | 1017 Map* map = object->map(); |
| 1018 ASSERT(map->IsMap()); | 1018 CHECK(map->IsMap()); |
| 1019 ASSERT(heap()->map_space()->Contains(map)); | 1019 CHECK(heap()->map_space()->Contains(map)); |
| 1020 | 1020 |
| 1021 // The object should not be code or a map. | 1021 // The object should not be code or a map. |
| 1022 ASSERT(!object->IsMap()); | 1022 CHECK(!object->IsMap()); |
| 1023 ASSERT(!object->IsCode()); | 1023 CHECK(!object->IsCode()); |
| 1024 | 1024 |
| 1025 // The object itself should look OK. | 1025 // The object itself should look OK. |
| 1026 object->Verify(); | 1026 object->Verify(); |
| 1027 | 1027 |
| 1028 // All the interior pointers should be contained in the heap. | 1028 // All the interior pointers should be contained in the heap. |
| 1029 VerifyPointersVisitor visitor; | 1029 VerifyPointersVisitor visitor; |
| 1030 int size = object->Size(); | 1030 int size = object->Size(); |
| 1031 object->IterateBody(map->instance_type(), size, &visitor); | 1031 object->IterateBody(map->instance_type(), size, &visitor); |
| 1032 | 1032 |
| 1033 current += size; | 1033 current += size; |
| 1034 } | 1034 } |
| 1035 | 1035 |
| 1036 // The allocation pointer should not be in the middle of an object. | 1036 // The allocation pointer should not be in the middle of an object. |
| 1037 ASSERT(current == top()); | 1037 ASSERT(current == top()); |
| 1038 |
| 1039 // Check semi-spaces. |
| 1040 ASSERT_EQ(from_space_.id(), kFromSpace); |
| 1041 ASSERT_EQ(to_space_.id(), kToSpace); |
| 1042 from_space_.Verify(); |
| 1043 to_space_.Verify(); |
| 1038 } | 1044 } |
| 1039 #endif | 1045 #endif |
| 1040 | 1046 |
| 1041 | 1047 |
| 1042 bool SemiSpace::Commit() { | 1048 bool SemiSpace::Commit() { |
| 1043 ASSERT(!is_committed()); | 1049 ASSERT(!is_committed()); |
| 1044 if (!heap()->isolate()->memory_allocator()->CommitBlock( | 1050 if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| 1045 start_, capacity_, executable())) { | 1051 start_, capacity_, executable())) { |
| 1046 return false; | 1052 return false; |
| 1047 } | 1053 } |
| 1048 committed_ = true; | 1054 committed_ = true; |
| 1049 // TODO(gc): When more than one page is present, initialize and | 1055 // TODO(gc): When more than one page is present, initialize and |
| 1050 // chain them all. | 1056 // chain them all. |
| 1051 current_page_ = NewSpacePage::Initialize(heap(), start_, id_); | 1057 NewSpacePage* page = NewSpacePage::Initialize(heap(), start_, this); |
| 1058 page->InsertAfter(&anchor_); |
| 1059 current_page_ = anchor_.next_page(); |
| 1052 return true; | 1060 return true; |
| 1053 } | 1061 } |
| 1054 | 1062 |
| 1055 | 1063 |
| 1056 bool SemiSpace::Uncommit() { | 1064 bool SemiSpace::Uncommit() { |
| 1057 ASSERT(is_committed()); | 1065 ASSERT(is_committed()); |
| 1058 if (!heap()->isolate()->memory_allocator()->UncommitBlock( | 1066 if (!heap()->isolate()->memory_allocator()->UncommitBlock( |
| 1059 start_, capacity_)) { | 1067 start_, capacity_)) { |
| 1060 return false; | 1068 return false; |
| 1061 } | 1069 } |
| 1062 committed_ = false; | 1070 committed_ = false; |
| 1063 return true; | 1071 return true; |
| 1064 } | 1072 } |
| 1065 | 1073 |
| 1066 | 1074 |
| 1075 void SemiSpace::Reset() { |
| 1076 ASSERT(anchor_.next_page() != &anchor_); |
| 1077 current_page_ = anchor_.next_page(); |
| 1078 } |
| 1079 |
| 1080 |
| 1081 void SemiSpace::Swap(SemiSpace* from, SemiSpace* to) { |
| 1082 // We won't be swapping semispaces without data in them. |
| 1083 ASSERT(from->anchor_.next_page() != &from->anchor_); |
| 1084 ASSERT(to->anchor_.next_page() != &to->anchor_); |
| 1085 |
| 1086 // Swap bits. |
| 1087 SemiSpace tmp = *from; |
| 1088 *from = *to; |
| 1089 *to = tmp; |
| 1090 |
| 1091 // Fixup back-pointers to the page list anchor now that its address |
| 1092 // has changed. |
| 1093 // Swap to/from-space bits on pages. |
| 1094 // Copy GC flags from old active space (from-space) to new (to-space). |
| 1095 intptr_t flags = from->current_page()->GetFlags(); |
| 1096 to->FlipPages(flags, NewSpacePage::kCopyOnFlipFlagsMask); |
| 1097 |
| 1098 from->FlipPages(0, 0); |
| 1099 } |
| 1100 |
| 1101 |
| 1067 // ----------------------------------------------------------------------------- | 1102 // ----------------------------------------------------------------------------- |
| 1068 // SemiSpace implementation | 1103 // SemiSpace implementation |
| 1069 | 1104 |
| 1070 bool SemiSpace::Setup(Address start, | 1105 bool SemiSpace::Setup(Address start, |
| 1071 int initial_capacity, | 1106 int initial_capacity, |
| 1072 int maximum_capacity) { | 1107 int maximum_capacity) { |
| 1073 // Creates a space in the young generation. The constructor does not | 1108 // Creates a space in the young generation. The constructor does not |
| 1074 // allocate memory from the OS. A SemiSpace is given a contiguous chunk of | 1109 // allocate memory from the OS. A SemiSpace is given a contiguous chunk of |
| 1075 // memory of size 'capacity' when set up, and does not grow or shrink | 1110 // memory of size 'capacity' when set up, and does not grow or shrink |
| 1076 // otherwise. In the mark-compact collector, the memory region of the from | 1111 // otherwise. In the mark-compact collector, the memory region of the from |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 ASSERT(IsAligned(delta, OS::AllocateAlignment())); | 1175 ASSERT(IsAligned(delta, OS::AllocateAlignment())); |
| 1141 if (!heap()->isolate()->memory_allocator()->UncommitBlock( | 1176 if (!heap()->isolate()->memory_allocator()->UncommitBlock( |
| 1142 high() - delta, delta)) { | 1177 high() - delta, delta)) { |
| 1143 return false; | 1178 return false; |
| 1144 } | 1179 } |
| 1145 capacity_ = new_capacity; | 1180 capacity_ = new_capacity; |
| 1146 return true; | 1181 return true; |
| 1147 } | 1182 } |
| 1148 | 1183 |
| 1149 | 1184 |
| 1150 void SemiSpace::Flip(intptr_t flags, intptr_t mask) { | 1185 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) { |
| 1186 anchor_.set_owner(this); |
| 1187 // Fixup back-pointers to anchor. Address of anchor changes |
| 1188 // when we swap. |
| 1189 anchor_.prev_page()->set_next_page(&anchor_); |
| 1190 anchor_.next_page()->set_prev_page(&anchor_); |
| 1191 |
| 1151 bool becomes_to_space = (id_ == kFromSpace); | 1192 bool becomes_to_space = (id_ == kFromSpace); |
| 1152 id_ = becomes_to_space ? kToSpace : kFromSpace; | 1193 id_ = becomes_to_space ? kToSpace : kFromSpace; |
| 1153 NewSpacePage* page = NewSpacePage::FromAddress(start_); | 1194 NewSpacePage* page = anchor_.next_page(); |
| 1154 while (page != NULL) { | 1195 while (page != &anchor_) { |
| 1196 page->set_owner(this); |
| 1155 page->SetFlags(flags, mask); | 1197 page->SetFlags(flags, mask); |
| 1156 if (becomes_to_space) { | 1198 if (becomes_to_space) { |
| 1157 page->ClearFlag(MemoryChunk::IN_FROM_SPACE); | 1199 page->ClearFlag(MemoryChunk::IN_FROM_SPACE); |
| 1158 page->SetFlag(MemoryChunk::IN_TO_SPACE); | 1200 page->SetFlag(MemoryChunk::IN_TO_SPACE); |
| 1159 } else { | 1201 } else { |
| 1160 page->SetFlag(MemoryChunk::IN_FROM_SPACE); | 1202 page->SetFlag(MemoryChunk::IN_FROM_SPACE); |
| 1161 page->ClearFlag(MemoryChunk::IN_TO_SPACE); | 1203 page->ClearFlag(MemoryChunk::IN_TO_SPACE); |
| 1162 } | 1204 } |
| 1163 page = page->next_page(); | 1205 page = page->next_page(); |
| 1164 } | 1206 } |
| 1165 } | 1207 } |
| 1166 | 1208 |
| 1167 #ifdef DEBUG | 1209 #ifdef DEBUG |
| 1168 void SemiSpace::Print() { } | 1210 void SemiSpace::Print() { } |
| 1169 | 1211 |
| 1170 | 1212 |
| 1171 void SemiSpace::Verify() { } | 1213 void SemiSpace::Verify() { |
| 1214 bool is_from_space = (id_ == kFromSpace); |
| 1215 NewSpacePage* page = anchor_.next_page(); |
| 1216 CHECK(anchor_.semi_space() == this); |
| 1217 while (page != &anchor_) { |
| 1218 CHECK(page->semi_space() == this); |
| 1219 CHECK(page->InNewSpace()); |
| 1220 CHECK(page->IsFlagSet(is_from_space ? MemoryChunk::IN_FROM_SPACE |
| 1221 : MemoryChunk::IN_TO_SPACE)); |
| 1222 CHECK(!page->IsFlagSet(is_from_space ? MemoryChunk::IN_TO_SPACE |
| 1223 : MemoryChunk::IN_FROM_SPACE)); |
| 1224 CHECK(page->prev_page()->next_page() == page); |
| 1225 page = page->next_page(); |
| 1226 } |
| 1227 } |
| 1172 #endif | 1228 #endif |
| 1173 | 1229 |
| 1174 | 1230 |
| 1175 // ----------------------------------------------------------------------------- | 1231 // ----------------------------------------------------------------------------- |
| 1176 // SemiSpaceIterator implementation. | 1232 // SemiSpaceIterator implementation. |
| 1177 SemiSpaceIterator::SemiSpaceIterator(NewSpace* space) { | 1233 SemiSpaceIterator::SemiSpaceIterator(NewSpace* space) { |
| 1178 Initialize(space, space->bottom(), space->top(), NULL); | 1234 Initialize(space, space->bottom(), space->top(), NULL); |
| 1179 } | 1235 } |
| 1180 | 1236 |
| 1181 | 1237 |
| (...skipping 1111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2293 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { | 2349 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { |
| 2294 if (obj->IsCode()) { | 2350 if (obj->IsCode()) { |
| 2295 Code* code = Code::cast(obj); | 2351 Code* code = Code::cast(obj); |
| 2296 isolate->code_kind_statistics()[code->kind()] += code->Size(); | 2352 isolate->code_kind_statistics()[code->kind()] += code->Size(); |
| 2297 } | 2353 } |
| 2298 } | 2354 } |
| 2299 } | 2355 } |
| 2300 #endif // DEBUG | 2356 #endif // DEBUG |
| 2301 | 2357 |
| 2302 } } // namespace v8::internal | 2358 } } // namespace v8::internal |
| OLD | NEW |