| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 return next_gc_likely_to_collect_more; | 760 return next_gc_likely_to_collect_more; |
| 761 } | 761 } |
| 762 | 762 |
| 763 | 763 |
| 764 int Heap::NotifyContextDisposed() { | 764 int Heap::NotifyContextDisposed() { |
| 765 if (FLAG_concurrent_recompilation) { | 765 if (FLAG_concurrent_recompilation) { |
| 766 // Flush the queued recompilation tasks. | 766 // Flush the queued recompilation tasks. |
| 767 isolate()->optimizing_compiler_thread()->Flush(); | 767 isolate()->optimizing_compiler_thread()->Flush(); |
| 768 } | 768 } |
| 769 flush_monomorphic_ics_ = true; | 769 flush_monomorphic_ics_ = true; |
| 770 AgeInlineCaches(); |
| 770 return ++contexts_disposed_; | 771 return ++contexts_disposed_; |
| 771 } | 772 } |
| 772 | 773 |
| 773 | 774 |
| 774 void Heap::PerformScavenge() { | 775 void Heap::PerformScavenge() { |
| 775 GCTracer tracer(this, NULL, NULL); | 776 GCTracer tracer(this, NULL, NULL); |
| 776 if (incremental_marking()->IsStopped()) { | 777 if (incremental_marking()->IsStopped()) { |
| 777 PerformGarbageCollection(SCAVENGER, &tracer); | 778 PerformGarbageCollection(SCAVENGER, &tracer); |
| 778 } else { | 779 } else { |
| 779 PerformGarbageCollection(MARK_COMPACTOR, &tracer); | 780 PerformGarbageCollection(MARK_COMPACTOR, &tracer); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 Heap* heap, | 833 Heap* heap, |
| 833 AllocationSpace space, | 834 AllocationSpace space, |
| 834 const char* gc_reason = NULL) { | 835 const char* gc_reason = NULL) { |
| 835 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask); | 836 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask); |
| 836 bool result = heap->CollectGarbage(space, gc_reason); | 837 bool result = heap->CollectGarbage(space, gc_reason); |
| 837 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags); | 838 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags); |
| 838 return result; | 839 return result; |
| 839 } | 840 } |
| 840 | 841 |
| 841 | 842 |
| 842 void Heap::ReserveSpace( | 843 void Heap::ReserveSpace(int *sizes, Address *locations_out) { |
| 843 int *sizes, | |
| 844 Address *locations_out) { | |
| 845 bool gc_performed = true; | 844 bool gc_performed = true; |
| 846 int counter = 0; | 845 int counter = 0; |
| 847 static const int kThreshold = 20; | 846 static const int kThreshold = 20; |
| 848 while (gc_performed && counter++ < kThreshold) { | 847 while (gc_performed && counter++ < kThreshold) { |
| 849 gc_performed = false; | 848 gc_performed = false; |
| 850 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1); | 849 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1); |
| 851 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { | 850 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { |
| 852 if (sizes[space] != 0) { | 851 if (sizes[space] != 0) { |
| 853 MaybeObject* allocation; | 852 MaybeObject* allocation; |
| 854 if (space == NEW_SPACE) { | 853 if (space == NEW_SPACE) { |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1157 MarkCompactPrologue(); | 1156 MarkCompactPrologue(); |
| 1158 | 1157 |
| 1159 mark_compact_collector_.CollectGarbage(); | 1158 mark_compact_collector_.CollectGarbage(); |
| 1160 | 1159 |
| 1161 LOG(isolate_, ResourceEvent("markcompact", "end")); | 1160 LOG(isolate_, ResourceEvent("markcompact", "end")); |
| 1162 | 1161 |
| 1163 gc_state_ = NOT_IN_GC; | 1162 gc_state_ = NOT_IN_GC; |
| 1164 | 1163 |
| 1165 isolate_->counters()->objs_since_last_full()->Set(0); | 1164 isolate_->counters()->objs_since_last_full()->Set(0); |
| 1166 | 1165 |
| 1167 contexts_disposed_ = 0; | |
| 1168 | |
| 1169 flush_monomorphic_ics_ = false; | 1166 flush_monomorphic_ics_ = false; |
| 1170 } | 1167 } |
| 1171 | 1168 |
| 1172 | 1169 |
| 1173 void Heap::MarkCompactPrologue() { | 1170 void Heap::MarkCompactPrologue() { |
| 1174 // At any old GC clear the keyed lookup cache to enable collection of unused | 1171 // At any old GC clear the keyed lookup cache to enable collection of unused |
| 1175 // maps. | 1172 // maps. |
| 1176 isolate_->keyed_lookup_cache()->Clear(); | 1173 isolate_->keyed_lookup_cache()->Clear(); |
| 1177 isolate_->context_slot_cache()->Clear(); | 1174 isolate_->context_slot_cache()->Clear(); |
| 1178 isolate_->descriptor_lookup_cache()->Clear(); | 1175 isolate_->descriptor_lookup_cache()->Clear(); |
| (...skipping 2931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4110 buffer[0] = static_cast<uint8_t>(code); | 4107 buffer[0] = static_cast<uint8_t>(code); |
| 4111 Object* result; | 4108 Object* result; |
| 4112 MaybeObject* maybe_result = | 4109 MaybeObject* maybe_result = |
| 4113 InternalizeOneByteString(Vector<const uint8_t>(buffer, 1)); | 4110 InternalizeOneByteString(Vector<const uint8_t>(buffer, 1)); |
| 4114 | 4111 |
| 4115 if (!maybe_result->ToObject(&result)) return maybe_result; | 4112 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4116 single_character_string_cache()->set(code, result); | 4113 single_character_string_cache()->set(code, result); |
| 4117 return result; | 4114 return result; |
| 4118 } | 4115 } |
| 4119 | 4116 |
| 4120 Object* result; | 4117 SeqTwoByteString* result; |
| 4121 { MaybeObject* maybe_result = AllocateRawTwoByteString(1); | 4118 { MaybeObject* maybe_result = AllocateRawTwoByteString(1); |
| 4122 if (!maybe_result->ToObject(&result)) return maybe_result; | 4119 if (!maybe_result->To<SeqTwoByteString>(&result)) return maybe_result; |
| 4123 } | 4120 } |
| 4124 String* answer = String::cast(result); | 4121 result->SeqTwoByteStringSet(0, code); |
| 4125 answer->Set(0, code); | 4122 return result; |
| 4126 return answer; | |
| 4127 } | 4123 } |
| 4128 | 4124 |
| 4129 | 4125 |
| 4130 MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) { | 4126 MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) { |
| 4131 if (length < 0 || length > ByteArray::kMaxLength) { | 4127 if (length < 0 || length > ByteArray::kMaxLength) { |
| 4132 return Failure::OutOfMemoryException(0x7); | 4128 return Failure::OutOfMemoryException(0x7); |
| 4133 } | 4129 } |
| 4134 int size = ByteArray::SizeFor(length); | 4130 int size = ByteArray::SizeFor(length); |
| 4135 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); | 4131 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); |
| 4136 Object* result; | 4132 Object* result; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4197 int obj_size = Code::SizeFor(body_size); | 4193 int obj_size = Code::SizeFor(body_size); |
| 4198 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); | 4194 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); |
| 4199 MaybeObject* maybe_result; | 4195 MaybeObject* maybe_result; |
| 4200 // Large code objects and code objects which should stay at a fixed address | 4196 // Large code objects and code objects which should stay at a fixed address |
| 4201 // are allocated in large object space. | 4197 // are allocated in large object space. |
| 4202 HeapObject* result; | 4198 HeapObject* result; |
| 4203 bool force_lo_space = obj_size > code_space()->AreaSize(); | 4199 bool force_lo_space = obj_size > code_space()->AreaSize(); |
| 4204 if (force_lo_space) { | 4200 if (force_lo_space) { |
| 4205 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); | 4201 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 4206 } else { | 4202 } else { |
| 4207 maybe_result = code_space_->AllocateRaw(obj_size); | 4203 maybe_result = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE); |
| 4208 } | 4204 } |
| 4209 if (!maybe_result->To<HeapObject>(&result)) return maybe_result; | 4205 if (!maybe_result->To<HeapObject>(&result)) return maybe_result; |
| 4210 | 4206 |
| 4211 if (immovable && !force_lo_space && | 4207 if (immovable && !force_lo_space && |
| 4212 // Objects on the first page of each space are never moved. | 4208 // Objects on the first page of each space are never moved. |
| 4213 !code_space_->FirstPage()->Contains(result->address())) { | 4209 !code_space_->FirstPage()->Contains(result->address())) { |
| 4214 // Discard the first code allocation, which was on a page where it could be | 4210 // Discard the first code allocation, which was on a page where it could be |
| 4215 // moved. | 4211 // moved. |
| 4216 CreateFillerObjectAt(result->address(), obj_size); | 4212 CreateFillerObjectAt(result->address(), obj_size); |
| 4217 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); | 4213 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4268 } | 4264 } |
| 4269 | 4265 |
| 4270 | 4266 |
| 4271 MaybeObject* Heap::CopyCode(Code* code) { | 4267 MaybeObject* Heap::CopyCode(Code* code) { |
| 4272 // Allocate an object the same size as the code object. | 4268 // Allocate an object the same size as the code object. |
| 4273 int obj_size = code->Size(); | 4269 int obj_size = code->Size(); |
| 4274 MaybeObject* maybe_result; | 4270 MaybeObject* maybe_result; |
| 4275 if (obj_size > code_space()->AreaSize()) { | 4271 if (obj_size > code_space()->AreaSize()) { |
| 4276 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); | 4272 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); |
| 4277 } else { | 4273 } else { |
| 4278 maybe_result = code_space_->AllocateRaw(obj_size); | 4274 maybe_result = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE); |
| 4279 } | 4275 } |
| 4280 | 4276 |
| 4281 Object* result; | 4277 Object* result; |
| 4282 if (!maybe_result->ToObject(&result)) return maybe_result; | 4278 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4283 | 4279 |
| 4284 // Copy code object. | 4280 // Copy code object. |
| 4285 Address old_addr = code->address(); | 4281 Address old_addr = code->address(); |
| 4286 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 4282 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| 4287 CopyBlock(new_addr, old_addr, obj_size); | 4283 CopyBlock(new_addr, old_addr, obj_size); |
| 4288 // Relocate the copy. | 4284 // Relocate the copy. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4311 | 4307 |
| 4312 Address old_addr = code->address(); | 4308 Address old_addr = code->address(); |
| 4313 | 4309 |
| 4314 size_t relocation_offset = | 4310 size_t relocation_offset = |
| 4315 static_cast<size_t>(code->instruction_end() - old_addr); | 4311 static_cast<size_t>(code->instruction_end() - old_addr); |
| 4316 | 4312 |
| 4317 MaybeObject* maybe_result; | 4313 MaybeObject* maybe_result; |
| 4318 if (new_obj_size > code_space()->AreaSize()) { | 4314 if (new_obj_size > code_space()->AreaSize()) { |
| 4319 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE); | 4315 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE); |
| 4320 } else { | 4316 } else { |
| 4321 maybe_result = code_space_->AllocateRaw(new_obj_size); | 4317 maybe_result = AllocateRaw(new_obj_size, CODE_SPACE, CODE_SPACE); |
| 4322 } | 4318 } |
| 4323 | 4319 |
| 4324 Object* result; | 4320 Object* result; |
| 4325 if (!maybe_result->ToObject(&result)) return maybe_result; | 4321 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4326 | 4322 |
| 4327 // Copy code object. | 4323 // Copy code object. |
| 4328 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); | 4324 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); |
| 4329 | 4325 |
| 4330 // Copy header and instructions. | 4326 // Copy header and instructions. |
| 4331 CopyBytes(new_addr, old_addr, relocation_offset); | 4327 CopyBytes(new_addr, old_addr, relocation_offset); |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4823 // Update write barrier for all fields that lie beyond the header. | 4819 // Update write barrier for all fields that lie beyond the header. |
| 4824 RecordWrites(clone_address, | 4820 RecordWrites(clone_address, |
| 4825 JSObject::kHeaderSize, | 4821 JSObject::kHeaderSize, |
| 4826 (object_size - JSObject::kHeaderSize) / kPointerSize); | 4822 (object_size - JSObject::kHeaderSize) / kPointerSize); |
| 4827 } else { | 4823 } else { |
| 4828 wb_mode = SKIP_WRITE_BARRIER; | 4824 wb_mode = SKIP_WRITE_BARRIER; |
| 4829 | 4825 |
| 4830 { int adjusted_object_size = site != NULL | 4826 { int adjusted_object_size = site != NULL |
| 4831 ? object_size + AllocationMemento::kSize | 4827 ? object_size + AllocationMemento::kSize |
| 4832 : object_size; | 4828 : object_size; |
| 4833 MaybeObject* maybe_clone = new_space_.AllocateRaw(adjusted_object_size); | 4829 MaybeObject* maybe_clone = |
| 4830 AllocateRaw(adjusted_object_size, NEW_SPACE, NEW_SPACE); |
| 4834 if (!maybe_clone->ToObject(&clone)) return maybe_clone; | 4831 if (!maybe_clone->ToObject(&clone)) return maybe_clone; |
| 4835 } | 4832 } |
| 4836 SLOW_ASSERT(InNewSpace(clone)); | 4833 SLOW_ASSERT(InNewSpace(clone)); |
| 4837 // Since we know the clone is allocated in new space, we can copy | 4834 // Since we know the clone is allocated in new space, we can copy |
| 4838 // the contents without worrying about updating the write barrier. | 4835 // the contents without worrying about updating the write barrier. |
| 4839 CopyBlock(HeapObject::cast(clone)->address(), | 4836 CopyBlock(HeapObject::cast(clone)->address(), |
| 4840 source->address(), | 4837 source->address(), |
| 4841 object_size); | 4838 object_size); |
| 4842 | 4839 |
| 4843 if (site != NULL) { | 4840 if (site != NULL) { |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5740 // Minimal hint that allows to do full GC. | 5737 // Minimal hint that allows to do full GC. |
| 5741 const int kMinHintForFullGC = 100; | 5738 const int kMinHintForFullGC = 100; |
| 5742 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4; | 5739 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4; |
| 5743 // The size factor is in range [5..250]. The numbers here are chosen from | 5740 // The size factor is in range [5..250]. The numbers here are chosen from |
| 5744 // experiments. If you changes them, make sure to test with | 5741 // experiments. If you changes them, make sure to test with |
| 5745 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.* | 5742 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.* |
| 5746 intptr_t step_size = | 5743 intptr_t step_size = |
| 5747 size_factor * IncrementalMarking::kAllocatedThreshold; | 5744 size_factor * IncrementalMarking::kAllocatedThreshold; |
| 5748 | 5745 |
| 5749 if (contexts_disposed_ > 0) { | 5746 if (contexts_disposed_ > 0) { |
| 5750 if (hint >= kMaxHint) { | 5747 contexts_disposed_ = 0; |
| 5751 // The embedder is requesting a lot of GC work after context disposal, | |
| 5752 // we age inline caches so that they don't keep objects from | |
| 5753 // the old context alive. | |
| 5754 AgeInlineCaches(); | |
| 5755 } | |
| 5756 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000); | 5748 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000); |
| 5757 if (hint >= mark_sweep_time && !FLAG_expose_gc && | 5749 if (hint >= mark_sweep_time && !FLAG_expose_gc && |
| 5758 incremental_marking()->IsStopped()) { | 5750 incremental_marking()->IsStopped()) { |
| 5759 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 5751 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 5760 CollectAllGarbage(kReduceMemoryFootprintMask, | 5752 CollectAllGarbage(kReduceMemoryFootprintMask, |
| 5761 "idle notification: contexts disposed"); | 5753 "idle notification: contexts disposed"); |
| 5762 } else { | 5754 } else { |
| 5763 AdvanceIdleIncrementalMarking(step_size); | 5755 AdvanceIdleIncrementalMarking(step_size); |
| 5764 contexts_disposed_ = 0; | |
| 5765 } | 5756 } |
| 5757 |
| 5766 // After context disposal there is likely a lot of garbage remaining, reset | 5758 // After context disposal there is likely a lot of garbage remaining, reset |
| 5767 // the idle notification counters in order to trigger more incremental GCs | 5759 // the idle notification counters in order to trigger more incremental GCs |
| 5768 // on subsequent idle notifications. | 5760 // on subsequent idle notifications. |
| 5769 StartIdleRound(); | 5761 StartIdleRound(); |
| 5770 return false; | 5762 return false; |
| 5771 } | 5763 } |
| 5772 | 5764 |
| 5773 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) { | 5765 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) { |
| 5774 return IdleGlobalGC(); | 5766 return IdleGlobalGC(); |
| 5775 } | 5767 } |
| (...skipping 2148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7924 if (FLAG_concurrent_recompilation) { | 7916 if (FLAG_concurrent_recompilation) { |
| 7925 heap_->relocation_mutex_->Lock(); | 7917 heap_->relocation_mutex_->Lock(); |
| 7926 #ifdef DEBUG | 7918 #ifdef DEBUG |
| 7927 heap_->relocation_mutex_locked_by_optimizer_thread_ = | 7919 heap_->relocation_mutex_locked_by_optimizer_thread_ = |
| 7928 heap_->isolate()->optimizing_compiler_thread()->IsOptimizerThread(); | 7920 heap_->isolate()->optimizing_compiler_thread()->IsOptimizerThread(); |
| 7929 #endif // DEBUG | 7921 #endif // DEBUG |
| 7930 } | 7922 } |
| 7931 } | 7923 } |
| 7932 | 7924 |
| 7933 } } // namespace v8::internal | 7925 } } // namespace v8::internal |
| OLD | NEW |