| 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 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 | 31 |
| 32 #include "execution.h" | 32 #include "execution.h" |
| 33 #include "mark-compact.h" | 33 #include "mark-compact.h" |
| 34 #include "objects.h" | 34 #include "objects.h" |
| 35 | 35 |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 | 39 |
| 40 // TODO(gc) rename into IncrementalMarker after merge. |
| 40 class IncrementalMarking : public AllStatic { | 41 class IncrementalMarking : public AllStatic { |
| 41 public: | 42 public: |
| 42 enum State { | 43 enum State { |
| 43 STOPPED, | 44 STOPPED, |
| 44 MARKING, | 45 MARKING, |
| 45 COMPLETE | 46 COMPLETE |
| 46 }; | 47 }; |
| 47 | 48 |
| 48 static State state() { | 49 explicit IncrementalMarking(Heap* heap); |
| 50 |
| 51 State state() { |
| 49 ASSERT(state_ == STOPPED || FLAG_incremental_marking); | 52 ASSERT(state_ == STOPPED || FLAG_incremental_marking); |
| 50 return state_; | 53 return state_; |
| 51 } | 54 } |
| 52 | 55 |
| 53 static bool should_hurry() { return should_hurry_; } | 56 bool should_hurry() { return should_hurry_; } |
| 54 | 57 |
| 55 static inline bool IsStopped() { return state() == STOPPED; } | 58 inline bool IsStopped() { return state() == STOPPED; } |
| 56 | 59 |
| 57 static bool WorthActivating(); | 60 inline bool IsMarking() { return state() == MARKING; } |
| 58 | 61 |
| 59 static void Start(); | 62 bool WorthActivating(); |
| 60 | 63 |
| 61 static void Stop(); | 64 void Start(); |
| 62 | 65 |
| 63 static void PrepareForScavenge(); | 66 void Stop(); |
| 64 | 67 |
| 65 static void UpdateMarkingStackAfterScavenge(); | 68 void PrepareForScavenge(); |
| 66 | 69 |
| 67 static void Hurry(); | 70 void UpdateMarkingStackAfterScavenge(); |
| 68 | 71 |
| 69 static void Finalize(); | 72 void Hurry(); |
| 70 | 73 |
| 71 static void MarkingComplete(); | 74 void Finalize(); |
| 75 |
| 76 void MarkingComplete(); |
| 72 | 77 |
| 73 // It's hard to know how much work the incremental marker should do to make | 78 // It's hard to know how much work the incremental marker should do to make |
| 74 // progress in the face of the mutator creating new work for it. We start | 79 // progress in the face of the mutator creating new work for it. We start |
| 75 // of at a moderate rate of work and gradually increase the speed of the | 80 // of at a moderate rate of work and gradually increase the speed of the |
| 76 // incremental marker until it completes. | 81 // incremental marker until it completes. |
| 77 // Do some marking every time this much memory has been allocated. | 82 // Do some marking every time this much memory has been allocated. |
| 78 static const intptr_t kAllocatedThreshold = 8192; | 83 static const intptr_t kAllocatedThreshold = 8192; |
| 79 // Start off by marking this many times more memory than has been allocated. | 84 // Start off by marking this many times more memory than has been allocated. |
| 80 static const intptr_t kInitialAllocationMarkingFactor = 4; | 85 static const intptr_t kInitialAllocationMarkingFactor = 4; |
| 81 // After this many steps we increase the marking/allocating factor. | 86 // After this many steps we increase the marking/allocating factor. |
| 82 static const intptr_t kAllocationMarkingFactorSpeedupInterval = 1024; | 87 static const intptr_t kAllocationMarkingFactorSpeedupInterval = 1024; |
| 83 // This is how much we increase the marking/allocating factor by. | 88 // This is how much we increase the marking/allocating factor by. |
| 84 static const intptr_t kAllocationMarkingFactorSpeedup = 4; | 89 static const intptr_t kAllocationMarkingFactorSpeedup = 4; |
| 85 | 90 |
| 86 static void Step(intptr_t allocated); | 91 void Step(intptr_t allocated); |
| 87 | 92 |
| 88 static inline void RestartIfNotMarking() { | 93 inline void RestartIfNotMarking() { |
| 89 if (state_ == COMPLETE) { | 94 if (state_ == COMPLETE) { |
| 90 state_ = MARKING; | 95 state_ = MARKING; |
| 91 if (FLAG_trace_incremental_marking) { | 96 if (FLAG_trace_incremental_marking) { |
| 92 PrintF("[IncrementalMarking] Restarting (new grey objects)\n"); | 97 PrintF("[IncrementalMarking] Restarting (new grey objects)\n"); |
| 93 } | 98 } |
| 94 } | 99 } |
| 95 } | 100 } |
| 96 | 101 |
| 97 static inline void RecordWrite(HeapObject* obj, Object* value) { | 102 static void RecordWriteFromCode(HeapObject* obj, |
| 98 if (!IsStopped() && value->IsHeapObject()) { | 103 Object* value, |
| 99 MarkBit value_bit = Marking::MarkBitFrom(HeapObject::cast(value)); | 104 Isolate* isolate); |
| 100 if (IsWhite(value_bit)) { | |
| 101 MarkBit obj_bit = Marking::MarkBitFrom(obj); | |
| 102 if (IsBlack(obj_bit)) { | |
| 103 BlackToGreyAndPush(obj, obj_bit); | |
| 104 RestartIfNotMarking(); | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 } | |
| 109 | 105 |
| 110 static inline void RecordWriteOf(HeapObject* value) { | 106 inline void RecordWrite(HeapObject* obj, Object* value); |
| 111 if (state_ != STOPPED) { | 107 inline void RecordWriteOf(HeapObject* value); |
| 112 MarkBit value_bit = Marking::MarkBitFrom(value); | 108 inline void RecordWrites(HeapObject* obj); |
| 113 if (IsWhite(value_bit)) { | |
| 114 WhiteToGreyAndPush(value, value_bit); | |
| 115 RestartIfNotMarking(); | |
| 116 } | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 | |
| 121 static inline void RecordWrites(HeapObject* obj) { | |
| 122 if (!IsStopped()) { | |
| 123 MarkBit obj_bit = Marking::MarkBitFrom(obj); | |
| 124 if (IsBlack(obj_bit)) { | |
| 125 BlackToGreyAndPush(obj, obj_bit); | |
| 126 RestartIfNotMarking(); | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | 109 |
| 131 // Impossible markbits: 01 | 110 // Impossible markbits: 01 |
| 132 static inline bool IsImpossible(MarkBit mark_bit) { | 111 static inline bool IsImpossible(MarkBit mark_bit) { |
| 133 return !mark_bit.Get() && mark_bit.Next().Get(); | 112 return !mark_bit.Get() && mark_bit.Next().Get(); |
| 134 } | 113 } |
| 135 | 114 |
| 136 // Black markbits: 10 - this is required by the sweeper. | 115 // Black markbits: 10 - this is required by the sweeper. |
| 137 static inline bool IsBlack(MarkBit mark_bit) { | 116 static inline bool IsBlack(MarkBit mark_bit) { |
| 138 ASSERT(!IsImpossible(mark_bit)); | 117 ASSERT(!IsImpossible(mark_bit)); |
| 139 return mark_bit.Get() && !mark_bit.Next().Get(); | 118 return mark_bit.Get() && !mark_bit.Next().Get(); |
| 140 } | 119 } |
| 141 | 120 |
| 142 // White markbits: 00 - this is required by the mark bit clearer. | 121 // White markbits: 00 - this is required by the mark bit clearer. |
| 143 static inline bool IsWhite(MarkBit mark_bit) { | 122 static inline bool IsWhite(MarkBit mark_bit) { |
| 144 ASSERT(!IsImpossible(mark_bit)); | 123 ASSERT(!IsImpossible(mark_bit)); |
| 145 return !mark_bit.Get(); | 124 return !mark_bit.Get(); |
| 146 } | 125 } |
| 147 | 126 |
| 148 // Grey markbits: 11 | 127 // Grey markbits: 11 |
| 149 static inline bool IsGrey(MarkBit mark_bit) { | 128 static inline bool IsGrey(MarkBit mark_bit) { |
| 150 ASSERT(!IsImpossible(mark_bit)); | 129 ASSERT(!IsImpossible(mark_bit)); |
| 151 return mark_bit.Get() && mark_bit.Next().Get(); | 130 return mark_bit.Get() && mark_bit.Next().Get(); |
| 152 } | 131 } |
| 153 | 132 |
| 154 static inline void BlackToGreyAndPush(HeapObject* obj, MarkBit mark_bit) { | 133 inline void BlackToGreyAndPush(HeapObject* obj, MarkBit mark_bit); |
| 155 ASSERT(Marking::MarkBitFrom(obj) == mark_bit); | |
| 156 ASSERT(obj->Size() >= 2*kPointerSize); | |
| 157 ASSERT(!IsStopped()); | |
| 158 ASSERT(IsBlack(mark_bit)); | |
| 159 mark_bit.Next().Set(); | |
| 160 ASSERT(IsGrey(mark_bit)); | |
| 161 | 134 |
| 162 marking_stack_.Push(obj); | 135 inline void WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit); |
| 163 ASSERT(!marking_stack_.overflowed()); | |
| 164 } | |
| 165 | 136 |
| 166 static inline void WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) { | 137 inline void WhiteToGrey(HeapObject* obj, MarkBit mark_bit); |
| 167 WhiteToGrey(obj, mark_bit); | |
| 168 marking_stack_.Push(obj); | |
| 169 ASSERT(!marking_stack_.overflowed()); | |
| 170 } | |
| 171 | 138 |
| 172 static inline void WhiteToGrey(HeapObject* obj, MarkBit mark_bit) { | 139 inline void MarkBlack(MarkBit mark_bit) { |
| 173 ASSERT(Marking::MarkBitFrom(obj) == mark_bit); | |
| 174 ASSERT(obj->Size() >= 2*kPointerSize); | |
| 175 ASSERT(!IsStopped()); | |
| 176 ASSERT(IsWhite(mark_bit)); | |
| 177 mark_bit.Set(); | |
| 178 mark_bit.Next().Set(); | |
| 179 ASSERT(IsGrey(mark_bit)); | |
| 180 } | |
| 181 | |
| 182 static inline void MarkBlack(MarkBit mark_bit) { | |
| 183 mark_bit.Set(); | 140 mark_bit.Set(); |
| 184 mark_bit.Next().Clear(); | 141 mark_bit.Next().Clear(); |
| 185 ASSERT(IsBlack(mark_bit)); | 142 ASSERT(IsBlack(mark_bit)); |
| 186 } | 143 } |
| 187 | 144 |
| 188 // Does white->black or grey->grey | 145 // Does white->black or grey->grey |
| 189 static inline void MarkBlackOrKeepGrey(MarkBit mark_bit) { | 146 inline void MarkBlackOrKeepGrey(MarkBit mark_bit) { |
| 190 ASSERT(!IsImpossible(mark_bit)); | 147 ASSERT(!IsImpossible(mark_bit)); |
| 191 if (mark_bit.Get()) return; | 148 if (mark_bit.Get()) return; |
| 192 mark_bit.Set(); | 149 mark_bit.Set(); |
| 193 ASSERT(!IsWhite(mark_bit)); | 150 ASSERT(!IsWhite(mark_bit)); |
| 194 ASSERT(!IsImpossible(mark_bit)); | 151 ASSERT(!IsImpossible(mark_bit)); |
| 195 } | 152 } |
| 196 | 153 |
| 197 static inline const char* ColorStr(MarkBit mark_bit) { | 154 static inline const char* ColorStr(MarkBit mark_bit) { |
| 198 if (IsBlack(mark_bit)) return "black"; | 155 if (IsBlack(mark_bit)) return "black"; |
| 199 if (IsWhite(mark_bit)) return "white"; | 156 if (IsWhite(mark_bit)) return "white"; |
| 200 if (IsGrey(mark_bit)) return "grey"; | 157 if (IsGrey(mark_bit)) return "grey"; |
| 201 UNREACHABLE(); | 158 UNREACHABLE(); |
| 202 return "???"; | 159 return "???"; |
| 203 } | 160 } |
| 204 | 161 |
| 205 enum ObjectColor { | 162 enum ObjectColor { |
| 206 BLACK_OBJECT, | 163 BLACK_OBJECT, |
| 207 WHITE_OBJECT, | 164 WHITE_OBJECT, |
| 208 GREY_OBJECT, | 165 GREY_OBJECT, |
| 209 IMPOSSIBLE_COLOR | 166 IMPOSSIBLE_COLOR |
| 210 }; | 167 }; |
| 211 | 168 |
| 212 static inline ObjectColor Color(HeapObject* obj) { | 169 inline ObjectColor Color(HeapObject* obj); |
| 213 MarkBit mark_bit = Marking::MarkBitFrom(obj); | |
| 214 if (IsBlack(mark_bit)) return BLACK_OBJECT; | |
| 215 if (IsWhite(mark_bit)) return WHITE_OBJECT; | |
| 216 if (IsGrey(mark_bit)) return GREY_OBJECT; | |
| 217 UNREACHABLE(); | |
| 218 return IMPOSSIBLE_COLOR; | |
| 219 } | |
| 220 | 170 |
| 221 static inline int steps_count() { | 171 inline int steps_count() { |
| 222 return steps_count_; | 172 return steps_count_; |
| 223 } | 173 } |
| 224 | 174 |
| 225 static inline double steps_took() { | 175 inline double steps_took() { |
| 226 return steps_took_; | 176 return steps_took_; |
| 227 } | 177 } |
| 228 | 178 |
| 229 private: | 179 private: |
| 230 static void set_should_hurry(bool val) { should_hurry_ = val; } | 180 void set_should_hurry(bool val) { |
| 231 static void ResetStepCounters() { | 181 should_hurry_ = val; |
| 182 } |
| 183 |
| 184 void ResetStepCounters() { |
| 232 steps_count_ = 0; | 185 steps_count_ = 0; |
| 233 steps_took_ = 0; | 186 steps_took_ = 0; |
| 234 allocation_marking_factor_ = kInitialAllocationMarkingFactor; | 187 allocation_marking_factor_ = kInitialAllocationMarkingFactor; |
| 235 } | 188 } |
| 236 | 189 |
| 237 | 190 |
| 238 static State state_; | 191 Heap* heap_; |
| 239 static MarkingStack marking_stack_; | |
| 240 | 192 |
| 241 static int steps_count_; | 193 State state_; |
| 242 static double steps_took_; | 194 MarkingStack marking_stack_; |
| 243 static bool should_hurry_; | 195 |
| 244 static intptr_t allocation_marking_factor_; | 196 int steps_count_; |
| 197 double steps_took_; |
| 198 bool should_hurry_; |
| 199 intptr_t allocation_marking_factor_; |
| 200 intptr_t allocated_; |
| 245 }; | 201 }; |
| 246 | 202 |
| 247 } } // namespace v8::internal | 203 } } // namespace v8::internal |
| 248 | 204 |
| 249 #endif // V8_INCREMENTAL_MARKING_H_ | 205 #endif // V8_INCREMENTAL_MARKING_H_ |
| OLD | NEW |