| 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 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 static void VerifyMarkbitsAreClean(PagedSpace* space) { | 276 static void VerifyMarkbitsAreClean(PagedSpace* space) { |
| 277 PageIterator it(space); | 277 PageIterator it(space); |
| 278 | 278 |
| 279 while (it.has_next()) { | 279 while (it.has_next()) { |
| 280 Page* p = it.next(); | 280 Page* p = it.next(); |
| 281 ASSERT(p->markbits()->IsClean()); | 281 ASSERT(p->markbits()->IsClean()); |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 | 284 |
| 285 static void VerifyMarkbitsAreClean(NewSpace* space) { | 285 static void VerifyMarkbitsAreClean(NewSpace* space) { |
| 286 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); | 286 NewSpacePageIterator it(space->bottom(), space->top()); |
| 287 | 287 |
| 288 while (it.has_next()) { | 288 while (it.has_next()) { |
| 289 NewSpacePage* p = it.next(); | 289 NewSpacePage* p = it.next(); |
| 290 ASSERT(p->markbits()->IsClean()); | 290 ASSERT(p->markbits()->IsClean()); |
| 291 } | 291 } |
| 292 } | 292 } |
| 293 | 293 |
| 294 static void VerifyMarkbitsAreClean(Heap* heap) { | 294 static void VerifyMarkbitsAreClean(Heap* heap) { |
| 295 VerifyMarkbitsAreClean(heap->old_pointer_space()); | 295 VerifyMarkbitsAreClean(heap->old_pointer_space()); |
| 296 VerifyMarkbitsAreClean(heap->old_data_space()); | 296 VerifyMarkbitsAreClean(heap->old_data_space()); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 ASSERT(!FLAG_always_compact || !FLAG_never_compact); | 415 ASSERT(!FLAG_always_compact || !FLAG_never_compact); |
| 416 | 416 |
| 417 if (FLAG_collect_maps) CreateBackPointers(); | 417 if (FLAG_collect_maps) CreateBackPointers(); |
| 418 #ifdef ENABLE_GDB_JIT_INTERFACE | 418 #ifdef ENABLE_GDB_JIT_INTERFACE |
| 419 if (FLAG_gdbjit) { | 419 if (FLAG_gdbjit) { |
| 420 // If GDBJIT interface is active disable compaction. | 420 // If GDBJIT interface is active disable compaction. |
| 421 compacting_collection_ = false; | 421 compacting_collection_ = false; |
| 422 } | 422 } |
| 423 #endif | 423 #endif |
| 424 | 424 |
| 425 if (heap()->incremental_marking()->IsMarking() && PreciseSweepingRequired()) { |
| 426 heap()->incremental_marking()->Abort(); |
| 427 } |
| 428 |
| 425 if (!FLAG_never_compact) StartCompaction(); | 429 if (!FLAG_never_compact) StartCompaction(); |
| 426 | 430 |
| 427 PagedSpaces spaces; | 431 PagedSpaces spaces; |
| 428 for (PagedSpace* space = spaces.next(); | 432 for (PagedSpace* space = spaces.next(); |
| 429 space != NULL; | 433 space != NULL; |
| 430 space = spaces.next()) { | 434 space = spaces.next()) { |
| 431 space->PrepareForMarkCompact(); | 435 space->PrepareForMarkCompact(); |
| 432 } | 436 } |
| 433 | 437 |
| 434 if (!heap()->incremental_marking()->IsMarking()) { | 438 if (!heap()->incremental_marking()->IsMarking()) { |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 void>::Visit); | 671 void>::Visit); |
| 668 | 672 |
| 669 | 673 |
| 670 table_.Register(kVisitFixedArray, | 674 table_.Register(kVisitFixedArray, |
| 671 &FlexibleBodyVisitor<StaticMarkingVisitor, | 675 &FlexibleBodyVisitor<StaticMarkingVisitor, |
| 672 FixedArray::BodyDescriptor, | 676 FixedArray::BodyDescriptor, |
| 673 void>::Visit); | 677 void>::Visit); |
| 674 | 678 |
| 675 table_.Register(kVisitGlobalContext, &VisitGlobalContext); | 679 table_.Register(kVisitGlobalContext, &VisitGlobalContext); |
| 676 | 680 |
| 681 table_.Register(kVisitFixedDoubleArray, DataObjectVisitor::Visit); |
| 682 |
| 677 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); | 683 table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); |
| 678 table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); | 684 table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit); |
| 679 table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); | 685 table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit); |
| 680 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); | 686 table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit); |
| 681 | 687 |
| 682 table_.Register(kVisitOddball, | 688 table_.Register(kVisitOddball, |
| 683 &FixedBodyVisitor<StaticMarkingVisitor, | 689 &FixedBodyVisitor<StaticMarkingVisitor, |
| 684 Oddball::BodyDescriptor, | 690 Oddball::BodyDescriptor, |
| 685 void>::Visit); | 691 void>::Visit); |
| 686 table_.Register(kVisitMap, | 692 table_.Register(kVisitMap, |
| 687 &FixedBodyVisitor<StaticMarkingVisitor, | 693 &FixedBodyVisitor<StaticMarkingVisitor, |
| 688 Map::BodyDescriptor, | 694 Map::BodyDescriptor, |
| 689 void>::Visit); | 695 void>::Visit); |
| 690 | 696 |
| 691 table_.Register(kVisitCode, &VisitCode); | 697 table_.Register(kVisitCode, &VisitCode); |
| 692 | 698 |
| 693 table_.Register(kVisitSharedFunctionInfo, | 699 table_.Register(kVisitSharedFunctionInfo, |
| 694 &VisitSharedFunctionInfoAndFlushCode); | 700 &VisitSharedFunctionInfoAndFlushCode); |
| 695 | 701 |
| 696 table_.Register(kVisitJSFunction, | 702 table_.Register(kVisitJSFunction, |
| 697 &VisitJSFunctionAndFlushCode); | 703 &VisitJSFunctionAndFlushCode); |
| 698 | 704 |
| 705 table_.Register(kVisitJSRegExp, |
| 706 &VisitRegExpAndFlushCode); |
| 707 |
| 699 table_.Register(kVisitPropertyCell, | 708 table_.Register(kVisitPropertyCell, |
| 700 &FixedBodyVisitor<StaticMarkingVisitor, | 709 &FixedBodyVisitor<StaticMarkingVisitor, |
| 701 JSGlobalPropertyCell::BodyDescriptor, | 710 JSGlobalPropertyCell::BodyDescriptor, |
| 702 void>::Visit); | 711 void>::Visit); |
| 703 | 712 |
| 704 table_.RegisterSpecializations<DataObjectVisitor, | 713 table_.RegisterSpecializations<DataObjectVisitor, |
| 705 kVisitDataObject, | 714 kVisitDataObject, |
| 706 kVisitDataObjectGeneric>(); | 715 kVisitDataObjectGeneric>(); |
| 707 | 716 |
| 708 table_.RegisterSpecializations<JSObjectVisitor, | 717 table_.RegisterSpecializations<JSObjectVisitor, |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>( | 852 reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>( |
| 844 map->GetHeap()); | 853 map->GetHeap()); |
| 845 } | 854 } |
| 846 | 855 |
| 847 // Code flushing support. | 856 // Code flushing support. |
| 848 | 857 |
| 849 // How many collections newly compiled code object will survive before being | 858 // How many collections newly compiled code object will survive before being |
| 850 // flushed. | 859 // flushed. |
| 851 static const int kCodeAgeThreshold = 5; | 860 static const int kCodeAgeThreshold = 5; |
| 852 | 861 |
| 862 static const int kRegExpCodeThreshold = 5; |
| 863 |
| 853 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { | 864 inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
| 854 Object* undefined = heap->undefined_value(); | 865 Object* undefined = heap->undefined_value(); |
| 855 return (info->script() != undefined) && | 866 return (info->script() != undefined) && |
| 856 (reinterpret_cast<Script*>(info->script())->source() != undefined); | 867 (reinterpret_cast<Script*>(info->script())->source() != undefined); |
| 857 } | 868 } |
| 858 | 869 |
| 859 | 870 |
| 860 inline static bool IsCompiled(JSFunction* function) { | 871 inline static bool IsCompiled(JSFunction* function) { |
| 861 return function->unchecked_code() != | 872 return function->unchecked_code() != |
| 862 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); | 873 function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 948 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); | 959 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); |
| 949 | 960 |
| 950 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); | 961 if (shared->IsInobjectSlackTrackingInProgress()) shared->DetachInitialMap(); |
| 951 | 962 |
| 952 FixedBodyVisitor<StaticMarkingVisitor, | 963 FixedBodyVisitor<StaticMarkingVisitor, |
| 953 SharedFunctionInfo::BodyDescriptor, | 964 SharedFunctionInfo::BodyDescriptor, |
| 954 void>::Visit(map, object); | 965 void>::Visit(map, object); |
| 955 } | 966 } |
| 956 | 967 |
| 957 | 968 |
| 969 static void UpdateRegExpCodeAgeAndFlush(Heap* heap, |
| 970 JSRegExp* re, |
| 971 bool is_ascii) { |
| 972 // Make sure that the fixed array is in fact initialized on the RegExp. |
| 973 // We could potentially trigger a GC when initializing the RegExp. |
| 974 if (HeapObject::cast(re->data())->map()->instance_type() != |
| 975 FIXED_ARRAY_TYPE) return; |
| 976 |
| 977 // Make sure this is a RegExp that actually contains code. |
| 978 if (re->TypeTagUnchecked() != JSRegExp::IRREGEXP) return; |
| 979 |
| 980 Object* code = re->DataAtUnchecked(JSRegExp::code_index(is_ascii)); |
| 981 if (!code->IsSmi() && |
| 982 HeapObject::cast(code)->map()->instance_type() == CODE_TYPE) { |
| 983 // Save a copy that can be reinstated if we need the code again. |
| 984 re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii), |
| 985 code, |
| 986 heap); |
| 987 // Set a number in the 0-255 range to guarantee no smi overflow. |
| 988 re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii), |
| 989 Smi::FromInt(heap->sweep_generation() & 0xff), |
| 990 heap); |
| 991 } else if (code->IsSmi()) { |
| 992 int value = Smi::cast(code)->value(); |
| 993 // The regexp has not been compiled yet or there was a compilation error. |
| 994 if (value == JSRegExp::kUninitializedValue || |
| 995 value == JSRegExp::kCompilationErrorValue) { |
| 996 return; |
| 997 } |
| 998 |
| 999 // Check if we should flush now. |
| 1000 if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) & 0xff)) { |
| 1001 re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii), |
| 1002 Smi::FromInt(JSRegExp::kUninitializedValue), |
| 1003 heap); |
| 1004 re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii), |
| 1005 Smi::FromInt(JSRegExp::kUninitializedValue), |
| 1006 heap); |
| 1007 } |
| 1008 } |
| 1009 } |
| 1010 |
| 1011 |
| 1012 // Works by setting the current sweep_generation (as a smi) in the |
| 1013 // code object place in the data array of the RegExp and keeps a copy |
| 1014 // around that can be reinstated if we reuse the RegExp before flushing. |
| 1015 // If we did not use the code for kRegExpCodeThreshold mark sweep GCs |
| 1016 // we flush the code. |
| 1017 static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) { |
| 1018 Heap* heap = map->GetHeap(); |
| 1019 MarkCompactCollector* collector = heap->mark_compact_collector(); |
| 1020 if (!collector->is_code_flushing_enabled()) { |
| 1021 VisitJSRegExpFields(map, object); |
| 1022 return; |
| 1023 } |
| 1024 JSRegExp* re = reinterpret_cast<JSRegExp*>(object); |
| 1025 // Flush code or set age on both ascii and two byte code. |
| 1026 UpdateRegExpCodeAgeAndFlush(heap, re, true); |
| 1027 UpdateRegExpCodeAgeAndFlush(heap, re, false); |
| 1028 // Visit the fields of the RegExp, including the updated FixedArray. |
| 1029 VisitJSRegExpFields(map, object); |
| 1030 } |
| 1031 |
| 1032 |
| 958 static void VisitSharedFunctionInfoAndFlushCode(Map* map, | 1033 static void VisitSharedFunctionInfoAndFlushCode(Map* map, |
| 959 HeapObject* object) { | 1034 HeapObject* object) { |
| 960 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); | 1035 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); |
| 961 if (!collector->is_code_flushing_enabled()) { | 1036 if (!collector->is_code_flushing_enabled()) { |
| 962 VisitSharedFunctionInfoGeneric(map, object); | 1037 VisitSharedFunctionInfoGeneric(map, object); |
| 963 return; | 1038 return; |
| 964 } | 1039 } |
| 965 VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false); | 1040 VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false); |
| 966 } | 1041 } |
| 967 | 1042 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1107 HeapObject::RawField(object, | 1182 HeapObject::RawField(object, |
| 1108 JSFunction::kNonWeakFieldsEndOffset)); | 1183 JSFunction::kNonWeakFieldsEndOffset)); |
| 1109 | 1184 |
| 1110 // Don't visit the next function list field as it is a weak reference. | 1185 // Don't visit the next function list field as it is a weak reference. |
| 1111 Object** next_function = | 1186 Object** next_function = |
| 1112 HeapObject::RawField(object, JSFunction::kNextFunctionLinkOffset); | 1187 HeapObject::RawField(object, JSFunction::kNextFunctionLinkOffset); |
| 1113 heap->mark_compact_collector()->RecordSlot( | 1188 heap->mark_compact_collector()->RecordSlot( |
| 1114 next_function, next_function, *next_function); | 1189 next_function, next_function, *next_function); |
| 1115 } | 1190 } |
| 1116 | 1191 |
| 1192 static inline void VisitJSRegExpFields(Map* map, |
| 1193 HeapObject* object) { |
| 1194 int last_property_offset = |
| 1195 JSRegExp::kSize + kPointerSize * map->inobject_properties(); |
| 1196 VisitPointers(map->GetHeap(), |
| 1197 SLOT_ADDR(object, JSRegExp::kPropertiesOffset), |
| 1198 SLOT_ADDR(object, last_property_offset)); |
| 1199 } |
| 1200 |
| 1117 | 1201 |
| 1118 static void VisitSharedFunctionInfoFields(Heap* heap, | 1202 static void VisitSharedFunctionInfoFields(Heap* heap, |
| 1119 HeapObject* object, | 1203 HeapObject* object, |
| 1120 bool flush_code_candidate) { | 1204 bool flush_code_candidate) { |
| 1121 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset)); | 1205 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kNameOffset)); |
| 1122 | 1206 |
| 1123 if (!flush_code_candidate) { | 1207 if (!flush_code_candidate) { |
| 1124 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset)); | 1208 VisitPointer(heap, SLOT_ADDR(object, SharedFunctionInfo::kCodeOffset)); |
| 1125 } | 1209 } |
| 1126 | 1210 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1146 explicit MarkingVisitor(Heap* heap) : heap_(heap) { } | 1230 explicit MarkingVisitor(Heap* heap) : heap_(heap) { } |
| 1147 | 1231 |
| 1148 void VisitPointer(Object** p) { | 1232 void VisitPointer(Object** p) { |
| 1149 StaticMarkingVisitor::VisitPointer(heap_, p); | 1233 StaticMarkingVisitor::VisitPointer(heap_, p); |
| 1150 } | 1234 } |
| 1151 | 1235 |
| 1152 void VisitPointers(Object** start, Object** end) { | 1236 void VisitPointers(Object** start, Object** end) { |
| 1153 StaticMarkingVisitor::VisitPointers(heap_, start, end); | 1237 StaticMarkingVisitor::VisitPointers(heap_, start, end); |
| 1154 } | 1238 } |
| 1155 | 1239 |
| 1156 void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) { | |
| 1157 StaticMarkingVisitor::VisitCodeTarget(heap, rinfo); | |
| 1158 } | |
| 1159 | |
| 1160 void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo) { | |
| 1161 StaticMarkingVisitor::VisitGlobalPropertyCell(heap, rinfo); | |
| 1162 } | |
| 1163 | |
| 1164 void VisitDebugTarget(Heap* heap, RelocInfo* rinfo) { | |
| 1165 StaticMarkingVisitor::VisitDebugTarget(heap, rinfo); | |
| 1166 } | |
| 1167 | |
| 1168 private: | 1240 private: |
| 1169 Heap* heap_; | 1241 Heap* heap_; |
| 1170 }; | 1242 }; |
| 1171 | 1243 |
| 1172 | 1244 |
| 1173 class CodeMarkingVisitor : public ThreadVisitor { | 1245 class CodeMarkingVisitor : public ThreadVisitor { |
| 1174 public: | 1246 public: |
| 1175 explicit CodeMarkingVisitor(MarkCompactCollector* collector) | 1247 explicit CodeMarkingVisitor(MarkCompactCollector* collector) |
| 1176 : collector_(collector) {} | 1248 : collector_(collector) {} |
| 1177 | 1249 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1322 // Set the entry to null_value (as deleted). | 1394 // Set the entry to null_value (as deleted). |
| 1323 *p = heap_->null_value(); | 1395 *p = heap_->null_value(); |
| 1324 pointers_removed_++; | 1396 pointers_removed_++; |
| 1325 } | 1397 } |
| 1326 } | 1398 } |
| 1327 } | 1399 } |
| 1328 | 1400 |
| 1329 int PointersRemoved() { | 1401 int PointersRemoved() { |
| 1330 return pointers_removed_; | 1402 return pointers_removed_; |
| 1331 } | 1403 } |
| 1404 |
| 1332 private: | 1405 private: |
| 1333 Heap* heap_; | 1406 Heap* heap_; |
| 1334 int pointers_removed_; | 1407 int pointers_removed_; |
| 1335 }; | 1408 }; |
| 1336 | 1409 |
| 1337 | 1410 |
| 1338 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects | 1411 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects |
| 1339 // are retained. | 1412 // are retained. |
| 1340 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { | 1413 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { |
| 1341 public: | 1414 public: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1353 ASSERT(IsMarked(object)); | 1426 ASSERT(IsMarked(object)); |
| 1354 ASSERT(HEAP->Contains(object)); | 1427 ASSERT(HEAP->Contains(object)); |
| 1355 if (object->IsMap()) { | 1428 if (object->IsMap()) { |
| 1356 Map* map = Map::cast(object); | 1429 Map* map = Map::cast(object); |
| 1357 if (FLAG_cleanup_code_caches_at_gc) { | 1430 if (FLAG_cleanup_code_caches_at_gc) { |
| 1358 map->ClearCodeCache(heap()); | 1431 map->ClearCodeCache(heap()); |
| 1359 } | 1432 } |
| 1360 | 1433 |
| 1361 // When map collection is enabled we have to mark through map's transitions | 1434 // When map collection is enabled we have to mark through map's transitions |
| 1362 // in a special way to make transition links weak. | 1435 // in a special way to make transition links weak. |
| 1363 // Only maps with instance types between FIRST_JS_OBJECT_TYPE and | 1436 // Only maps for subclasses of JSReceiver can have transitions. |
| 1364 // JS_FUNCTION_TYPE can have transitions. | 1437 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); |
| 1365 if (FLAG_collect_maps && | 1438 if (FLAG_collect_maps && map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { |
| 1366 map->instance_type() >= FIRST_JS_OBJECT_TYPE && | |
| 1367 map->instance_type() <= JS_FUNCTION_TYPE) { | |
| 1368 MarkMapContents(map); | 1439 MarkMapContents(map); |
| 1369 } else { | 1440 } else { |
| 1370 marking_deque_.PushBlack(map); | 1441 marking_deque_.PushBlack(map); |
| 1371 } | 1442 } |
| 1372 } else { | 1443 } else { |
| 1373 marking_deque_.PushBlack(object); | 1444 marking_deque_.PushBlack(object); |
| 1374 } | 1445 } |
| 1375 } | 1446 } |
| 1376 | 1447 |
| 1377 | 1448 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 marking_deque_.PushBlack(descriptors); | 1524 marking_deque_.PushBlack(descriptors); |
| 1454 } | 1525 } |
| 1455 | 1526 |
| 1456 | 1527 |
| 1457 void MarkCompactCollector::CreateBackPointers() { | 1528 void MarkCompactCollector::CreateBackPointers() { |
| 1458 HeapObjectIterator iterator(heap()->map_space()); | 1529 HeapObjectIterator iterator(heap()->map_space()); |
| 1459 for (HeapObject* next_object = iterator.Next(); | 1530 for (HeapObject* next_object = iterator.Next(); |
| 1460 next_object != NULL; next_object = iterator.Next()) { | 1531 next_object != NULL; next_object = iterator.Next()) { |
| 1461 if (next_object->IsMap()) { // Could also be FreeSpace object on free list. | 1532 if (next_object->IsMap()) { // Could also be FreeSpace object on free list. |
| 1462 Map* map = Map::cast(next_object); | 1533 Map* map = Map::cast(next_object); |
| 1463 if (map->instance_type() >= FIRST_JS_OBJECT_TYPE && | 1534 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1464 map->instance_type() <= JS_FUNCTION_TYPE) { | 1535 if (map->instance_type() >= FIRST_JS_RECEIVER_TYPE) { |
| 1465 map->CreateBackPointers(); | 1536 map->CreateBackPointers(); |
| 1466 } else { | 1537 } else { |
| 1467 ASSERT(map->instance_descriptors() == heap()->empty_descriptor_array()); | 1538 ASSERT(map->instance_descriptors() == heap()->empty_descriptor_array()); |
| 1468 } | 1539 } |
| 1469 } | 1540 } |
| 1470 } | 1541 } |
| 1471 } | 1542 } |
| 1472 | 1543 |
| 1473 | 1544 |
| 1474 // Fill the marking stack with overflowed objects returned by the given | 1545 // Fill the marking stack with overflowed objects returned by the given |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1848 | 1919 |
| 1849 // Repeat host application specific marking to mark unmarked objects | 1920 // Repeat host application specific marking to mark unmarked objects |
| 1850 // reachable from the weak roots. | 1921 // reachable from the weak roots. |
| 1851 ProcessExternalMarking(); | 1922 ProcessExternalMarking(); |
| 1852 | 1923 |
| 1853 AfterMarking(); | 1924 AfterMarking(); |
| 1854 } | 1925 } |
| 1855 | 1926 |
| 1856 | 1927 |
| 1857 void MarkCompactCollector::AfterMarking() { | 1928 void MarkCompactCollector::AfterMarking() { |
| 1929 // Object literal map caches reference symbols (cache keys) and maps |
| 1930 // (cache values). At this point still useful maps have already been |
| 1931 // marked. Mark the keys for the alive values before we process the |
| 1932 // symbol table. |
| 1933 ProcessMapCaches(); |
| 1934 |
| 1858 // Prune the symbol table removing all symbols only pointed to by the | 1935 // Prune the symbol table removing all symbols only pointed to by the |
| 1859 // symbol table. Cannot use symbol_table() here because the symbol | 1936 // symbol table. Cannot use symbol_table() here because the symbol |
| 1860 // table is marked. | 1937 // table is marked. |
| 1861 SymbolTable* symbol_table = heap()->symbol_table(); | 1938 SymbolTable* symbol_table = heap()->symbol_table(); |
| 1862 SymbolTableCleaner v(heap()); | 1939 SymbolTableCleaner v(heap()); |
| 1863 symbol_table->IterateElements(&v); | 1940 symbol_table->IterateElements(&v); |
| 1864 symbol_table->ElementsRemoved(v.PointersRemoved()); | 1941 symbol_table->ElementsRemoved(v.PointersRemoved()); |
| 1865 heap()->external_string_table_.Iterate(&v); | 1942 heap()->external_string_table_.Iterate(&v); |
| 1866 heap()->external_string_table_.CleanUp(); | 1943 heap()->external_string_table_.CleanUp(); |
| 1867 | 1944 |
| 1868 // Process the weak references. | 1945 // Process the weak references. |
| 1869 MarkCompactWeakObjectRetainer mark_compact_object_retainer; | 1946 MarkCompactWeakObjectRetainer mark_compact_object_retainer; |
| 1870 heap()->ProcessWeakReferences(&mark_compact_object_retainer); | 1947 heap()->ProcessWeakReferences(&mark_compact_object_retainer); |
| 1871 | 1948 |
| 1872 // Remove object groups after marking phase. | 1949 // Remove object groups after marking phase. |
| 1873 heap()->isolate()->global_handles()->RemoveObjectGroups(); | 1950 heap()->isolate()->global_handles()->RemoveObjectGroups(); |
| 1874 heap()->isolate()->global_handles()->RemoveImplicitRefGroups(); | 1951 heap()->isolate()->global_handles()->RemoveImplicitRefGroups(); |
| 1875 | 1952 |
| 1876 // Flush code from collected candidates. | 1953 // Flush code from collected candidates. |
| 1877 if (is_code_flushing_enabled()) { | 1954 if (is_code_flushing_enabled()) { |
| 1878 code_flusher_->ProcessCandidates(); | 1955 code_flusher_->ProcessCandidates(); |
| 1879 } | 1956 } |
| 1880 | 1957 |
| 1881 // Clean up dead objects from the runtime profiler. | 1958 // Clean up dead objects from the runtime profiler. |
| 1882 heap()->isolate()->runtime_profiler()->RemoveDeadSamples(); | 1959 heap()->isolate()->runtime_profiler()->RemoveDeadSamples(); |
| 1883 } | 1960 } |
| 1884 | 1961 |
| 1885 | 1962 |
| 1963 void MarkCompactCollector::ProcessMapCaches() { |
| 1964 Object* raw_context = heap()->global_contexts_list_; |
| 1965 while (raw_context != heap()->undefined_value()) { |
| 1966 Context* context = reinterpret_cast<Context*>(raw_context); |
| 1967 if (IsMarked(context)) { |
| 1968 HeapObject* raw_map_cache = |
| 1969 HeapObject::cast(context->get(Context::MAP_CACHE_INDEX)); |
| 1970 // A map cache may be reachable from the stack. In this case |
| 1971 // it's already transitively marked and it's too late to clean |
| 1972 // up its parts. |
| 1973 if (!IsMarked(raw_map_cache) && |
| 1974 raw_map_cache != heap()->undefined_value()) { |
| 1975 MapCache* map_cache = reinterpret_cast<MapCache*>(raw_map_cache); |
| 1976 int existing_elements = map_cache->NumberOfElements(); |
| 1977 int used_elements = 0; |
| 1978 for (int i = MapCache::kElementsStartIndex; |
| 1979 i < map_cache->length(); |
| 1980 i += MapCache::kEntrySize) { |
| 1981 Object* raw_key = map_cache->get(i); |
| 1982 if (raw_key == heap()->undefined_value() || |
| 1983 raw_key == heap()->null_value()) continue; |
| 1984 STATIC_ASSERT(MapCache::kEntrySize == 2); |
| 1985 Object* raw_map = map_cache->get(i + 1); |
| 1986 if (raw_map->IsHeapObject() && IsMarked(raw_map)) { |
| 1987 ++used_elements; |
| 1988 } else { |
| 1989 // Delete useless entries with unmarked maps. |
| 1990 ASSERT(raw_map->IsMap()); |
| 1991 map_cache->set_null_unchecked(heap(), i); |
| 1992 map_cache->set_null_unchecked(heap(), i + 1); |
| 1993 } |
| 1994 } |
| 1995 if (used_elements == 0) { |
| 1996 context->set(Context::MAP_CACHE_INDEX, heap()->undefined_value()); |
| 1997 } else { |
| 1998 // Note: we don't actually shrink the cache here to avoid |
| 1999 // extra complexity during GC. We rely on subsequent cache |
| 2000 // usages (EnsureCapacity) to do this. |
| 2001 map_cache->ElementsRemoved(existing_elements - used_elements); |
| 2002 MarkBit map_cache_markbit = Marking::MarkBitFrom(map_cache); |
| 2003 MarkObject(map_cache, map_cache_markbit); |
| 2004 } |
| 2005 } |
| 2006 } |
| 2007 // Move to next element in the list. |
| 2008 raw_context = context->get(Context::NEXT_CONTEXT_LINK); |
| 2009 } |
| 2010 ProcessMarkingDeque(); |
| 2011 } |
| 2012 |
| 2013 |
| 1886 #ifdef DEBUG | 2014 #ifdef DEBUG |
| 1887 void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) { | 2015 void MarkCompactCollector::UpdateLiveObjectCount(HeapObject* obj) { |
| 1888 live_bytes_ += obj->Size(); | 2016 live_bytes_ += obj->Size(); |
| 1889 if (heap()->new_space()->Contains(obj)) { | 2017 if (heap()->new_space()->Contains(obj)) { |
| 1890 live_young_objects_size_ += obj->Size(); | 2018 live_young_objects_size_ += obj->Size(); |
| 1891 } else if (heap()->map_space()->Contains(obj)) { | 2019 } else if (heap()->map_space()->Contains(obj)) { |
| 1892 ASSERT(obj->IsMap()); | 2020 ASSERT(obj->IsMap()); |
| 1893 live_map_objects_size_ += obj->Size(); | 2021 live_map_objects_size_ += obj->Size(); |
| 1894 } else if (heap()->cell_space()->Contains(obj)) { | 2022 } else if (heap()->cell_space()->Contains(obj)) { |
| 1895 ASSERT(obj->IsJSGlobalPropertyCell()); | 2023 ASSERT(obj->IsJSGlobalPropertyCell()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1922 // All of these actions are carried out only on maps of JSObjects | 2050 // All of these actions are carried out only on maps of JSObjects |
| 1923 // and related subtypes. | 2051 // and related subtypes. |
| 1924 for (HeapObject* obj = map_iterator.Next(); | 2052 for (HeapObject* obj = map_iterator.Next(); |
| 1925 obj != NULL; obj = map_iterator.Next()) { | 2053 obj != NULL; obj = map_iterator.Next()) { |
| 1926 Map* map = reinterpret_cast<Map*>(obj); | 2054 Map* map = reinterpret_cast<Map*>(obj); |
| 1927 MarkBit map_mark = Marking::MarkBitFrom(map); | 2055 MarkBit map_mark = Marking::MarkBitFrom(map); |
| 1928 if (map->IsFreeSpace()) continue; | 2056 if (map->IsFreeSpace()) continue; |
| 1929 | 2057 |
| 1930 ASSERT(map->IsMap()); | 2058 ASSERT(map->IsMap()); |
| 1931 // Only JSObject and subtypes have map transitions and back pointers. | 2059 // Only JSObject and subtypes have map transitions and back pointers. |
| 1932 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; | 2060 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1933 if (map->instance_type() > JS_FUNCTION_TYPE) continue; | 2061 if (map->instance_type() < FIRST_JS_RECEIVER_TYPE) continue; |
| 1934 | 2062 |
| 1935 if (map_mark.Get() && | 2063 if (map_mark.Get() && |
| 1936 map->attached_to_shared_function_info()) { | 2064 map->attached_to_shared_function_info()) { |
| 1937 // This map is used for inobject slack tracking and has been detached | 2065 // This map is used for inobject slack tracking and has been detached |
| 1938 // from SharedFunctionInfo during the mark phase. | 2066 // from SharedFunctionInfo during the mark phase. |
| 1939 // Since it survived the GC, reattach it now. | 2067 // Since it survived the GC, reattach it now. |
| 1940 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); | 2068 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); |
| 1941 } | 2069 } |
| 1942 | 2070 |
| 1943 // Clear dead prototype transitions. | 2071 // Clear dead prototype transitions. |
| 2072 int number_of_transitions = map->NumberOfProtoTransitions(); |
| 1944 FixedArray* prototype_transitions = map->prototype_transitions(); | 2073 FixedArray* prototype_transitions = map->prototype_transitions(); |
| 1945 if (prototype_transitions->length() > 0) { | |
| 1946 int finger = Smi::cast(prototype_transitions->get(0))->value(); | |
| 1947 int new_finger = 1; | |
| 1948 for (int i = 1; i < finger; i += 2) { | |
| 1949 HeapObject* prototype = HeapObject::cast(prototype_transitions->get(i)); | |
| 1950 Map* cached_map = Map::cast(prototype_transitions->get(i + 1)); | |
| 1951 MarkBit prototype_mark = Marking::MarkBitFrom(prototype); | |
| 1952 MarkBit cached_map_mark = Marking::MarkBitFrom(cached_map); | |
| 1953 if (prototype_mark.Get() && cached_map_mark.Get()) { | |
| 1954 if (new_finger != i) { | |
| 1955 prototype_transitions->set_unchecked(heap_, | |
| 1956 new_finger, | |
| 1957 prototype, | |
| 1958 UPDATE_WRITE_BARRIER); | |
| 1959 prototype_transitions->set_unchecked(heap_, | |
| 1960 new_finger + 1, | |
| 1961 cached_map, | |
| 1962 SKIP_WRITE_BARRIER); | |
| 1963 } | |
| 1964 | 2074 |
| 1965 Object** prototype_slot = | 2075 int new_number_of_transitions = 0; |
| 1966 prototype_transitions->data_start() + new_finger; | 2076 const int header = Map::kProtoTransitionHeaderSize; |
| 1967 RecordSlot(prototype_slot, prototype_slot, prototype); | 2077 const int proto_offset = |
| 1968 new_finger += 2; | 2078 header + Map::kProtoTransitionPrototypeOffset; |
| 2079 const int map_offset = header + Map::kProtoTransitionMapOffset; |
| 2080 const int step = Map::kProtoTransitionElementsPerEntry; |
| 2081 for (int i = 0; i < number_of_transitions; i++) { |
| 2082 Object* prototype = prototype_transitions->get(proto_offset + i * step); |
| 2083 Object* cached_map = prototype_transitions->get(map_offset + i * step); |
| 2084 if (IsMarked(prototype) && IsMarked(cached_map)) { |
| 2085 if (new_number_of_transitions != i) { |
| 2086 prototype_transitions->set_unchecked( |
| 2087 heap_, |
| 2088 proto_offset + new_number_of_transitions * step, |
| 2089 prototype, |
| 2090 UPDATE_WRITE_BARRIER); |
| 2091 prototype_transitions->set_unchecked( |
| 2092 heap_, |
| 2093 map_offset + new_number_of_transitions * step, |
| 2094 cached_map, |
| 2095 SKIP_WRITE_BARRIER); |
| 1969 } | 2096 } |
| 2097 new_number_of_transitions++; |
| 1970 } | 2098 } |
| 1971 | 2099 |
| 1972 // Fill slots that became free with undefined value. | 2100 // Fill slots that became free with undefined value. |
| 1973 Object* undefined = heap()->undefined_value(); | 2101 Object* undefined = heap()->undefined_value(); |
| 1974 for (int i = new_finger; i < finger; i++) { | 2102 for (int i = new_number_of_transitions * step; |
| 2103 i < number_of_transitions * step; |
| 2104 i++) { |
| 1975 prototype_transitions->set_unchecked(heap_, | 2105 prototype_transitions->set_unchecked(heap_, |
| 1976 i, | 2106 header + i, |
| 1977 undefined, | 2107 undefined, |
| 1978 SKIP_WRITE_BARRIER); | 2108 SKIP_WRITE_BARRIER); |
| 1979 | 2109 |
| 1980 // TODO(gc) we should not evacuate first page of data space. | 2110 // TODO(gc) we should not evacuate first page of data space. |
| 1981 // but we are doing it now to increase coverage. | 2111 // but we are doing it now to increase coverage. |
| 1982 Object** undefined_slot = | 2112 Object** undefined_slot = |
| 1983 prototype_transitions->data_start() + i; | 2113 prototype_transitions->data_start() + i; |
| 1984 RecordSlot(undefined_slot, undefined_slot, undefined); | 2114 RecordSlot(undefined_slot, undefined_slot, undefined); |
| 1985 } | 2115 } |
| 1986 prototype_transitions->set_unchecked(0, Smi::FromInt(new_finger)); | 2116 map->SetNumberOfProtoTransitions(new_number_of_transitions); |
| 1987 } | 2117 } |
| 1988 | 2118 |
| 1989 // Follow the chain of back pointers to find the prototype. | 2119 // Follow the chain of back pointers to find the prototype. |
| 1990 Map* current = map; | 2120 Map* current = map; |
| 1991 while (current->IsMap()) { | 2121 while (current->IsMap()) { |
| 1992 current = reinterpret_cast<Map*>(current->prototype()); | 2122 current = reinterpret_cast<Map*>(current->prototype()); |
| 1993 ASSERT(current->IsHeapObject()); | 2123 ASSERT(current->IsHeapObject()); |
| 1994 } | 2124 } |
| 1995 Object* real_prototype = current; | 2125 Object* real_prototype = current; |
| 1996 | 2126 |
| (...skipping 1193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3190 while (buffer != NULL) { | 3320 while (buffer != NULL) { |
| 3191 SlotsBuffer* next_buffer = buffer->next(); | 3321 SlotsBuffer* next_buffer = buffer->next(); |
| 3192 DeallocateBuffer(buffer); | 3322 DeallocateBuffer(buffer); |
| 3193 buffer = next_buffer; | 3323 buffer = next_buffer; |
| 3194 } | 3324 } |
| 3195 *buffer_address = NULL; | 3325 *buffer_address = NULL; |
| 3196 } | 3326 } |
| 3197 | 3327 |
| 3198 | 3328 |
| 3199 } } // namespace v8::internal | 3329 } } // namespace v8::internal |
| OLD | NEW |