| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 "v8.h" | 5 #include "v8.h" |
| 6 | 6 |
| 7 #include "accessors.h" | 7 #include "accessors.h" |
| 8 #include "api.h" | 8 #include "api.h" |
| 9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
| 10 #include "codegen.h" | 10 #include "codegen.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 lo_space_(NULL), | 77 lo_space_(NULL), |
| 78 gc_state_(NOT_IN_GC), | 78 gc_state_(NOT_IN_GC), |
| 79 gc_post_processing_depth_(0), | 79 gc_post_processing_depth_(0), |
| 80 ms_count_(0), | 80 ms_count_(0), |
| 81 gc_count_(0), | 81 gc_count_(0), |
| 82 remembered_unmapped_pages_index_(0), | 82 remembered_unmapped_pages_index_(0), |
| 83 unflattened_strings_length_(0), | 83 unflattened_strings_length_(0), |
| 84 #ifdef DEBUG | 84 #ifdef DEBUG |
| 85 allocation_timeout_(0), | 85 allocation_timeout_(0), |
| 86 #endif // DEBUG | 86 #endif // DEBUG |
| 87 new_space_high_promotion_mode_active_(false), | |
| 88 old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit), | 87 old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit), |
| 89 size_of_old_gen_at_last_old_space_gc_(0), | 88 size_of_old_gen_at_last_old_space_gc_(0), |
| 90 external_allocation_limit_(0), | 89 external_allocation_limit_(0), |
| 91 amount_of_external_allocated_memory_(0), | 90 amount_of_external_allocated_memory_(0), |
| 92 amount_of_external_allocated_memory_at_last_global_gc_(0), | 91 amount_of_external_allocated_memory_at_last_global_gc_(0), |
| 93 old_gen_exhausted_(false), | 92 old_gen_exhausted_(false), |
| 94 inline_allocation_disabled_(false), | 93 inline_allocation_disabled_(false), |
| 95 store_buffer_rebuilder_(store_buffer()), | 94 store_buffer_rebuilder_(store_buffer()), |
| 96 hidden_string_(NULL), | 95 hidden_string_(NULL), |
| 97 gc_safe_size_of_old_object_(NULL), | 96 gc_safe_size_of_old_object_(NULL), |
| 98 total_regexp_code_generated_(0), | 97 total_regexp_code_generated_(0), |
| 99 tracer_(NULL), | 98 tracer_(NULL), |
| 100 high_survival_rate_period_length_(0), | 99 high_survival_rate_period_length_(0), |
| 101 low_survival_rate_period_length_(0), | |
| 102 survival_rate_(0), | |
| 103 promoted_objects_size_(0), | 100 promoted_objects_size_(0), |
| 104 promotion_rate_(0), | 101 promotion_rate_(0), |
| 105 semi_space_copied_object_size_(0), | 102 semi_space_copied_object_size_(0), |
| 106 semi_space_copied_rate_(0), | 103 semi_space_copied_rate_(0), |
| 107 previous_survival_rate_trend_(Heap::STABLE), | |
| 108 survival_rate_trend_(Heap::STABLE), | |
| 109 max_gc_pause_(0.0), | 104 max_gc_pause_(0.0), |
| 110 total_gc_time_ms_(0.0), | 105 total_gc_time_ms_(0.0), |
| 111 max_alive_after_gc_(0), | 106 max_alive_after_gc_(0), |
| 112 min_in_mutator_(kMaxInt), | 107 min_in_mutator_(kMaxInt), |
| 113 alive_after_last_gc_(0), | 108 alive_after_last_gc_(0), |
| 114 last_gc_end_timestamp_(0.0), | 109 last_gc_end_timestamp_(0.0), |
| 115 marking_time_(0.0), | 110 marking_time_(0.0), |
| 116 sweeping_time_(0.0), | 111 sweeping_time_(0.0), |
| 117 mark_compact_collector_(this), | 112 mark_compact_collector_(this), |
| 118 store_buffer_(this), | 113 store_buffer_(this), |
| (...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 Object* cache = | 1001 Object* cache = |
| 1007 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX); | 1002 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX); |
| 1008 if (!cache->IsUndefined()) { | 1003 if (!cache->IsUndefined()) { |
| 1009 NormalizedMapCache::cast(cache)->Clear(); | 1004 NormalizedMapCache::cast(cache)->Clear(); |
| 1010 } | 1005 } |
| 1011 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 1006 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 1012 } | 1007 } |
| 1013 } | 1008 } |
| 1014 | 1009 |
| 1015 | 1010 |
| 1016 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { | 1011 void Heap::UpdateSurvivalStatistics(int start_new_space_size) { |
| 1017 if (start_new_space_size == 0) return; | 1012 if (start_new_space_size == 0) return; |
| 1018 | 1013 |
| 1019 promotion_rate_ = | 1014 promotion_rate_ = |
| 1020 (static_cast<double>(promoted_objects_size_) / | 1015 (static_cast<double>(promoted_objects_size_) / |
| 1021 static_cast<double>(start_new_space_size) * 100); | 1016 static_cast<double>(start_new_space_size) * 100); |
| 1022 | 1017 |
| 1023 semi_space_copied_rate_ = | 1018 semi_space_copied_rate_ = |
| 1024 (static_cast<double>(semi_space_copied_object_size_) / | 1019 (static_cast<double>(semi_space_copied_object_size_) / |
| 1025 static_cast<double>(start_new_space_size) * 100); | 1020 static_cast<double>(start_new_space_size) * 100); |
| 1026 | 1021 |
| 1027 double survival_rate = promotion_rate_ + semi_space_copied_rate_; | 1022 double survival_rate = promotion_rate_ + semi_space_copied_rate_; |
| 1028 | 1023 |
| 1029 if (survival_rate > kYoungSurvivalRateHighThreshold) { | 1024 if (survival_rate > kYoungSurvivalRateHighThreshold) { |
| 1030 high_survival_rate_period_length_++; | 1025 high_survival_rate_period_length_++; |
| 1031 } else { | 1026 } else { |
| 1032 high_survival_rate_period_length_ = 0; | 1027 high_survival_rate_period_length_ = 0; |
| 1033 } | 1028 } |
| 1034 | |
| 1035 if (survival_rate < kYoungSurvivalRateLowThreshold) { | |
| 1036 low_survival_rate_period_length_++; | |
| 1037 } else { | |
| 1038 low_survival_rate_period_length_ = 0; | |
| 1039 } | |
| 1040 | |
| 1041 double survival_rate_diff = survival_rate_ - survival_rate; | |
| 1042 | |
| 1043 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) { | |
| 1044 set_survival_rate_trend(DECREASING); | |
| 1045 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) { | |
| 1046 set_survival_rate_trend(INCREASING); | |
| 1047 } else { | |
| 1048 set_survival_rate_trend(STABLE); | |
| 1049 } | |
| 1050 | |
| 1051 survival_rate_ = survival_rate; | |
| 1052 } | 1029 } |
| 1053 | 1030 |
| 1054 bool Heap::PerformGarbageCollection( | 1031 bool Heap::PerformGarbageCollection( |
| 1055 GarbageCollector collector, | 1032 GarbageCollector collector, |
| 1056 GCTracer* tracer, | 1033 GCTracer* tracer, |
| 1057 const v8::GCCallbackFlags gc_callback_flags) { | 1034 const v8::GCCallbackFlags gc_callback_flags) { |
| 1058 bool next_gc_likely_to_collect_more = false; | 1035 bool next_gc_likely_to_collect_more = false; |
| 1059 | 1036 |
| 1060 if (collector != SCAVENGER) { | 1037 if (collector != SCAVENGER) { |
| 1061 PROFILE(isolate_, CodeMovingGCEvent()); | 1038 PROFILE(isolate_, CodeMovingGCEvent()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 old_generation_allocation_limit_ = | 1078 old_generation_allocation_limit_ = |
| 1102 OldGenerationAllocationLimit(size_of_old_gen_at_last_old_space_gc_); | 1079 OldGenerationAllocationLimit(size_of_old_gen_at_last_old_space_gc_); |
| 1103 | 1080 |
| 1104 old_gen_exhausted_ = false; | 1081 old_gen_exhausted_ = false; |
| 1105 } else { | 1082 } else { |
| 1106 tracer_ = tracer; | 1083 tracer_ = tracer; |
| 1107 Scavenge(); | 1084 Scavenge(); |
| 1108 tracer_ = NULL; | 1085 tracer_ = NULL; |
| 1109 } | 1086 } |
| 1110 | 1087 |
| 1111 UpdateSurvivalRateTrend(start_new_space_size); | 1088 UpdateSurvivalStatistics(start_new_space_size); |
| 1112 | |
| 1113 if (!new_space_high_promotion_mode_active_ && | |
| 1114 new_space_.Capacity() == new_space_.MaximumCapacity() && | |
| 1115 IsStableOrIncreasingSurvivalTrend() && | |
| 1116 IsHighSurvivalRate()) { | |
| 1117 // Stable high survival rates even though young generation is at | |
| 1118 // maximum capacity indicates that most objects will be promoted. | |
| 1119 // To decrease scavenger pauses and final mark-sweep pauses, we | |
| 1120 // have to limit maximal capacity of the young generation. | |
| 1121 SetNewSpaceHighPromotionModeActive(true); | |
| 1122 if (FLAG_trace_gc) { | |
| 1123 PrintPID("Limited new space size due to high promotion rate: %d MB\n", | |
| 1124 new_space_.InitialCapacity() / MB); | |
| 1125 } | |
| 1126 // The high promotion mode is our indicator to turn on pretenuring. We have | |
| 1127 // to deoptimize all optimized code in global pretenuring mode and all | |
| 1128 // code which should be tenured in local pretenuring mode. | |
| 1129 if (FLAG_pretenuring) { | |
| 1130 if (!FLAG_allocation_site_pretenuring) { | |
| 1131 isolate_->stack_guard()->RequestFullDeopt(); | |
| 1132 } | |
| 1133 } | |
| 1134 } else if (new_space_high_promotion_mode_active_ && | |
| 1135 IsStableOrDecreasingSurvivalTrend() && | |
| 1136 IsLowSurvivalRate()) { | |
| 1137 // Decreasing low survival rates might indicate that the above high | |
| 1138 // promotion mode is over and we should allow the young generation | |
| 1139 // to grow again. | |
| 1140 SetNewSpaceHighPromotionModeActive(false); | |
| 1141 if (FLAG_trace_gc) { | |
| 1142 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n", | |
| 1143 new_space_.MaximumCapacity() / MB); | |
| 1144 } | |
| 1145 // Trigger deoptimization here to turn off global pretenuring as soon as | |
| 1146 // possible. | |
| 1147 if (FLAG_pretenuring && !FLAG_allocation_site_pretenuring) { | |
| 1148 isolate_->stack_guard()->RequestFullDeopt(); | |
| 1149 } | |
| 1150 } | |
| 1151 | |
| 1152 if (new_space_high_promotion_mode_active_ && | |
| 1153 new_space_.Capacity() > new_space_.InitialCapacity()) { | |
| 1154 new_space_.Shrink(); | |
| 1155 } | |
| 1156 | 1089 |
| 1157 isolate_->counters()->objs_since_last_young()->Set(0); | 1090 isolate_->counters()->objs_since_last_young()->Set(0); |
| 1158 | 1091 |
| 1159 // Callbacks that fire after this point might trigger nested GCs and | 1092 // Callbacks that fire after this point might trigger nested GCs and |
| 1160 // restart incremental marking, the assertion can't be moved down. | 1093 // restart incremental marking, the assertion can't be moved down. |
| 1161 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); | 1094 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); |
| 1162 | 1095 |
| 1163 gc_post_processing_depth_++; | 1096 gc_post_processing_depth_++; |
| 1164 { AllowHeapAllocation allow_allocation; | 1097 { AllowHeapAllocation allow_allocation; |
| 1165 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 1098 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1346 for (HeapObject* object = data_it.Next(); | 1279 for (HeapObject* object = data_it.Next(); |
| 1347 object != NULL; object = data_it.Next()) | 1280 object != NULL; object = data_it.Next()) |
| 1348 object->Iterate(&v); | 1281 object->Iterate(&v); |
| 1349 } | 1282 } |
| 1350 } | 1283 } |
| 1351 #endif // VERIFY_HEAP | 1284 #endif // VERIFY_HEAP |
| 1352 | 1285 |
| 1353 | 1286 |
| 1354 void Heap::CheckNewSpaceExpansionCriteria() { | 1287 void Heap::CheckNewSpaceExpansionCriteria() { |
| 1355 if (new_space_.Capacity() < new_space_.MaximumCapacity() && | 1288 if (new_space_.Capacity() < new_space_.MaximumCapacity() && |
| 1356 survived_since_last_expansion_ > new_space_.Capacity() && | 1289 survived_since_last_expansion_ > new_space_.Capacity()) { |
| 1357 !new_space_high_promotion_mode_active_) { | |
| 1358 // Grow the size of new space if there is room to grow, enough data | 1290 // Grow the size of new space if there is room to grow, enough data |
| 1359 // has survived scavenge since the last expansion and we are not in | 1291 // has survived scavenge since the last expansion and we are not in |
| 1360 // high promotion mode. | 1292 // high promotion mode. |
| 1361 new_space_.Grow(); | 1293 new_space_.Grow(); |
| 1362 survived_since_last_expansion_ = 0; | 1294 survived_since_last_expansion_ = 0; |
| 1363 } | 1295 } |
| 1364 } | 1296 } |
| 1365 | 1297 |
| 1366 | 1298 |
| 1367 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { | 1299 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { |
| (...skipping 4828 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6196 in_free_list_or_wasted_before_gc_); | 6128 in_free_list_or_wasted_before_gc_); |
| 6197 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize(heap_)); | 6129 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize(heap_)); |
| 6198 | 6130 |
| 6199 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); | 6131 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); |
| 6200 PrintF("promoted=%" V8_PTR_PREFIX "d ", heap_->promoted_objects_size_); | 6132 PrintF("promoted=%" V8_PTR_PREFIX "d ", heap_->promoted_objects_size_); |
| 6201 PrintF("semi_space_copied=%" V8_PTR_PREFIX "d ", | 6133 PrintF("semi_space_copied=%" V8_PTR_PREFIX "d ", |
| 6202 heap_->semi_space_copied_object_size_); | 6134 heap_->semi_space_copied_object_size_); |
| 6203 PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_); | 6135 PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_); |
| 6204 PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_); | 6136 PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_); |
| 6205 PrintF("nodes_promoted=%d ", nodes_promoted_); | 6137 PrintF("nodes_promoted=%d ", nodes_promoted_); |
| 6206 PrintF("survival_rate=%.1f%% ", heap_->survival_rate_); | |
| 6207 PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_); | 6138 PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_); |
| 6208 PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_); | 6139 PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_); |
| 6209 | 6140 |
| 6210 if (collector_ == SCAVENGER) { | 6141 if (collector_ == SCAVENGER) { |
| 6211 PrintF("stepscount=%d ", steps_count_since_last_gc_); | 6142 PrintF("stepscount=%d ", steps_count_since_last_gc_); |
| 6212 PrintF("stepstook=%.1f ", steps_took_since_last_gc_); | 6143 PrintF("stepstook=%.1f ", steps_took_since_last_gc_); |
| 6213 } else { | 6144 } else { |
| 6214 PrintF("stepscount=%d ", steps_count_); | 6145 PrintF("stepscount=%d ", steps_count_); |
| 6215 PrintF("stepstook=%.1f ", steps_took_); | 6146 PrintF("stepstook=%.1f ", steps_took_); |
| 6216 PrintF("longeststep=%.1f ", longest_step_); | 6147 PrintF("longeststep=%.1f ", longest_step_); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6492 static_cast<int>(object_sizes_last_time_[index])); | 6423 static_cast<int>(object_sizes_last_time_[index])); |
| 6493 CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT) | 6424 CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT) |
| 6494 #undef ADJUST_LAST_TIME_OBJECT_COUNT | 6425 #undef ADJUST_LAST_TIME_OBJECT_COUNT |
| 6495 | 6426 |
| 6496 OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 6427 OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); |
| 6497 OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 6428 OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); |
| 6498 ClearObjectStats(); | 6429 ClearObjectStats(); |
| 6499 } | 6430 } |
| 6500 | 6431 |
| 6501 } } // namespace v8::internal | 6432 } } // namespace v8::internal |
| OLD | NEW |