ysr@777: /* xdono@1014: * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. ysr@777: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ysr@777: * ysr@777: * This code is free software; you can redistribute it and/or modify it ysr@777: * under the terms of the GNU General Public License version 2 only, as ysr@777: * published by the Free Software Foundation. ysr@777: * ysr@777: * This code is distributed in the hope that it will be useful, but WITHOUT ysr@777: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ysr@777: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ysr@777: * version 2 for more details (a copy is included in the LICENSE file that ysr@777: * accompanied this code). ysr@777: * ysr@777: * You should have received a copy of the GNU General Public License version ysr@777: * 2 along with this work; if not, write to the Free Software Foundation, ysr@777: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ysr@777: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: ysr@777: class G1CollectedHeap; ysr@777: class CMTask; ysr@777: typedef GenericTaskQueue CMTaskQueue; ysr@777: typedef GenericTaskQueueSet CMTaskQueueSet; ysr@777: ysr@777: // A generic CM bit map. This is essentially a wrapper around the BitMap ysr@777: // class, with one bit per (1<<_shifter) HeapWords. ysr@777: apetrusenko@984: class CMBitMapRO VALUE_OBJ_CLASS_SPEC { ysr@777: protected: ysr@777: HeapWord* _bmStartWord; // base address of range covered by map ysr@777: size_t _bmWordSize; // map size (in #HeapWords covered) ysr@777: const int _shifter; // map to char or bit ysr@777: VirtualSpace _virtual_space; // underlying the bit map ysr@777: BitMap _bm; // the bit map itself ysr@777: ysr@777: public: ysr@777: // constructor ysr@777: CMBitMapRO(ReservedSpace rs, int shifter); ysr@777: ysr@777: enum { do_yield = true }; ysr@777: ysr@777: // inquiries ysr@777: HeapWord* startWord() const { return _bmStartWord; } ysr@777: size_t sizeInWords() const { return _bmWordSize; } ysr@777: // the following is one past the last word in space ysr@777: HeapWord* endWord() const { return _bmStartWord + _bmWordSize; } ysr@777: ysr@777: // read marks ysr@777: ysr@777: bool isMarked(HeapWord* addr) const { ysr@777: assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), ysr@777: "outside underlying space?"); ysr@777: return _bm.at(heapWordToOffset(addr)); ysr@777: } ysr@777: ysr@777: // iteration ysr@777: bool iterate(BitMapClosure* cl) { return _bm.iterate(cl); } ysr@777: bool iterate(BitMapClosure* cl, MemRegion mr); ysr@777: ysr@777: // Return the address corresponding to the next marked bit at or after ysr@777: // "addr", and before "limit", if "limit" is non-NULL. If there is no ysr@777: // such bit, returns "limit" if that is non-NULL, or else "endWord()". ysr@777: HeapWord* getNextMarkedWordAddress(HeapWord* addr, ysr@777: HeapWord* limit = NULL) const; ysr@777: // Return the address corresponding to the next unmarked bit at or after ysr@777: // "addr", and before "limit", if "limit" is non-NULL. If there is no ysr@777: // such bit, returns "limit" if that is non-NULL, or else "endWord()". ysr@777: HeapWord* getNextUnmarkedWordAddress(HeapWord* addr, ysr@777: HeapWord* limit = NULL) const; ysr@777: ysr@777: // conversion utilities ysr@777: // XXX Fix these so that offsets are size_t's... ysr@777: HeapWord* offsetToHeapWord(size_t offset) const { ysr@777: return _bmStartWord + (offset << _shifter); ysr@777: } ysr@777: size_t heapWordToOffset(HeapWord* addr) const { ysr@777: return pointer_delta(addr, _bmStartWord) >> _shifter; ysr@777: } ysr@777: int heapWordDiffToOffsetDiff(size_t diff) const; ysr@777: HeapWord* nextWord(HeapWord* addr) { ysr@777: return offsetToHeapWord(heapWordToOffset(addr) + 1); ysr@777: } ysr@777: ysr@777: void mostly_disjoint_range_union(BitMap* from_bitmap, ysr@777: size_t from_start_index, ysr@777: HeapWord* to_start_word, ysr@777: size_t word_num); ysr@777: ysr@777: // debugging ysr@777: NOT_PRODUCT(bool covers(ReservedSpace rs) const;) ysr@777: }; ysr@777: ysr@777: class CMBitMap : public CMBitMapRO { ysr@777: ysr@777: public: ysr@777: // constructor ysr@777: CMBitMap(ReservedSpace rs, int shifter) : ysr@777: CMBitMapRO(rs, shifter) {} ysr@777: ysr@777: // write marks ysr@777: void mark(HeapWord* addr) { ysr@777: assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), ysr@777: "outside underlying space?"); ysr@777: _bm.at_put(heapWordToOffset(addr), true); ysr@777: } ysr@777: void clear(HeapWord* addr) { ysr@777: assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), ysr@777: "outside underlying space?"); ysr@777: _bm.at_put(heapWordToOffset(addr), false); ysr@777: } ysr@777: bool parMark(HeapWord* addr) { ysr@777: assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), ysr@777: "outside underlying space?"); ysr@777: return _bm.par_at_put(heapWordToOffset(addr), true); ysr@777: } ysr@777: bool parClear(HeapWord* addr) { ysr@777: assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize), ysr@777: "outside underlying space?"); ysr@777: return _bm.par_at_put(heapWordToOffset(addr), false); ysr@777: } ysr@777: void markRange(MemRegion mr); ysr@777: void clearAll(); ysr@777: void clearRange(MemRegion mr); ysr@777: ysr@777: // Starting at the bit corresponding to "addr" (inclusive), find the next ysr@777: // "1" bit, if any. This bit starts some run of consecutive "1"'s; find ysr@777: // the end of this run (stopping at "end_addr"). Return the MemRegion ysr@777: // covering from the start of the region corresponding to the first bit ysr@777: // of the run to the end of the region corresponding to the last bit of ysr@777: // the run. If there is no "1" bit at or after "addr", return an empty ysr@777: // MemRegion. ysr@777: MemRegion getAndClearMarkedRegion(HeapWord* addr, HeapWord* end_addr); ysr@777: }; ysr@777: ysr@777: // Represents a marking stack used by the CM collector. ysr@777: // Ideally this should be GrowableArray<> just like MSC's marking stack(s). apetrusenko@984: class CMMarkStack VALUE_OBJ_CLASS_SPEC { ysr@777: ConcurrentMark* _cm; ysr@777: oop* _base; // bottom of stack ysr@777: jint _index; // one more than last occupied index ysr@777: jint _capacity; // max #elements ysr@777: jint _oops_do_bound; // Number of elements to include in next iteration. ysr@777: NOT_PRODUCT(jint _max_depth;) // max depth plumbed during run ysr@777: ysr@777: bool _overflow; ysr@777: DEBUG_ONLY(bool _drain_in_progress;) ysr@777: DEBUG_ONLY(bool _drain_in_progress_yields;) ysr@777: ysr@777: public: ysr@777: CMMarkStack(ConcurrentMark* cm); ysr@777: ~CMMarkStack(); ysr@777: ysr@777: void allocate(size_t size); ysr@777: ysr@777: oop pop() { ysr@777: if (!isEmpty()) { ysr@777: return _base[--_index] ; ysr@777: } ysr@777: return NULL; ysr@777: } ysr@777: ysr@777: // If overflow happens, don't do the push, and record the overflow. ysr@777: // *Requires* that "ptr" is already marked. ysr@777: void push(oop ptr) { ysr@777: if (isFull()) { ysr@777: // Record overflow. ysr@777: _overflow = true; ysr@777: return; ysr@777: } else { ysr@777: _base[_index++] = ptr; ysr@777: NOT_PRODUCT(_max_depth = MAX2(_max_depth, _index)); ysr@777: } ysr@777: } ysr@777: // Non-block impl. Note: concurrency is allowed only with other ysr@777: // "par_push" operations, not with "pop" or "drain". We would need ysr@777: // parallel versions of them if such concurrency was desired. ysr@777: void par_push(oop ptr); ysr@777: ysr@777: // Pushes the first "n" elements of "ptr_arr" on the stack. ysr@777: // Non-block impl. Note: concurrency is allowed only with other ysr@777: // "par_adjoin_arr" or "push" operations, not with "pop" or "drain". ysr@777: void par_adjoin_arr(oop* ptr_arr, int n); ysr@777: ysr@777: // Pushes the first "n" elements of "ptr_arr" on the stack. ysr@777: // Locking impl: concurrency is allowed only with ysr@777: // "par_push_arr" and/or "par_pop_arr" operations, which use the same ysr@777: // locking strategy. ysr@777: void par_push_arr(oop* ptr_arr, int n); ysr@777: ysr@777: // If returns false, the array was empty. Otherwise, removes up to "max" ysr@777: // elements from the stack, and transfers them to "ptr_arr" in an ysr@777: // unspecified order. The actual number transferred is given in "n" ("n ysr@777: // == 0" is deliberately redundant with the return value.) Locking impl: ysr@777: // concurrency is allowed only with "par_push_arr" and/or "par_pop_arr" ysr@777: // operations, which use the same locking strategy. ysr@777: bool par_pop_arr(oop* ptr_arr, int max, int* n); ysr@777: ysr@777: // Drain the mark stack, applying the given closure to all fields of ysr@777: // objects on the stack. (That is, continue until the stack is empty, ysr@777: // even if closure applications add entries to the stack.) The "bm" ysr@777: // argument, if non-null, may be used to verify that only marked objects ysr@777: // are on the mark stack. If "yield_after" is "true", then the ysr@777: // concurrent marker performing the drain offers to yield after ysr@777: // processing each object. If a yield occurs, stops the drain operation ysr@777: // and returns false. Otherwise, returns true. ysr@777: template ysr@777: bool drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after = false); ysr@777: ysr@777: bool isEmpty() { return _index == 0; } ysr@777: bool isFull() { return _index == _capacity; } ysr@777: int maxElems() { return _capacity; } ysr@777: ysr@777: bool overflow() { return _overflow; } ysr@777: void clear_overflow() { _overflow = false; } ysr@777: ysr@777: int size() { return _index; } ysr@777: ysr@777: void setEmpty() { _index = 0; clear_overflow(); } ysr@777: ysr@777: // Record the current size; a subsequent "oops_do" will iterate only over ysr@777: // indices valid at the time of this call. ysr@777: void set_oops_do_bound(jint bound = -1) { ysr@777: if (bound == -1) { ysr@777: _oops_do_bound = _index; ysr@777: } else { ysr@777: _oops_do_bound = bound; ysr@777: } ysr@777: } ysr@777: jint oops_do_bound() { return _oops_do_bound; } ysr@777: // iterate over the oops in the mark stack, up to the bound recorded via ysr@777: // the call above. ysr@777: void oops_do(OopClosure* f); ysr@777: }; ysr@777: apetrusenko@984: class CMRegionStack VALUE_OBJ_CLASS_SPEC { ysr@777: MemRegion* _base; ysr@777: jint _capacity; ysr@777: jint _index; ysr@777: jint _oops_do_bound; ysr@777: bool _overflow; ysr@777: public: ysr@777: CMRegionStack(); ysr@777: ~CMRegionStack(); ysr@777: void allocate(size_t size); ysr@777: ysr@777: // This is lock-free; assumes that it will only be called in parallel ysr@777: // with other "push" operations (no pops). ysr@777: void push(MemRegion mr); ysr@777: ysr@777: // Lock-free; assumes that it will only be called in parallel ysr@777: // with other "pop" operations (no pushes). ysr@777: MemRegion pop(); ysr@777: ysr@777: bool isEmpty() { return _index == 0; } ysr@777: bool isFull() { return _index == _capacity; } ysr@777: ysr@777: bool overflow() { return _overflow; } ysr@777: void clear_overflow() { _overflow = false; } ysr@777: ysr@777: int size() { return _index; } ysr@777: ysr@777: // It iterates over the entries in the region stack and it ysr@777: // invalidates (i.e. assigns MemRegion()) the ones that point to ysr@777: // regions in the collection set. ysr@777: bool invalidate_entries_into_cset(); ysr@777: ysr@777: // This gives an upper bound up to which the iteration in ysr@777: // invalidate_entries_into_cset() will reach. This prevents ysr@777: // newly-added entries to be unnecessarily scanned. ysr@777: void set_oops_do_bound() { ysr@777: _oops_do_bound = _index; ysr@777: } ysr@777: ysr@777: void setEmpty() { _index = 0; clear_overflow(); } ysr@777: }; ysr@777: ysr@777: // this will enable a variety of different statistics per GC task ysr@777: #define _MARKING_STATS_ 0 ysr@777: // this will enable the higher verbose levels ysr@777: #define _MARKING_VERBOSE_ 0 ysr@777: ysr@777: #if _MARKING_STATS_ ysr@777: #define statsOnly(statement) \ ysr@777: do { \ ysr@777: statement ; \ ysr@777: } while (0) ysr@777: #else // _MARKING_STATS_ ysr@777: #define statsOnly(statement) \ ysr@777: do { \ ysr@777: } while (0) ysr@777: #endif // _MARKING_STATS_ ysr@777: ysr@777: // Some extra guarantees that I like to also enable in optimised mode ysr@777: // when debugging. If you want to enable them, comment out the assert ysr@777: // macro and uncomment out the guaratee macro ysr@777: // #define tmp_guarantee_CM(expr, str) guarantee(expr, str) ysr@777: #define tmp_guarantee_CM(expr, str) assert(expr, str) ysr@777: ysr@777: typedef enum { ysr@777: no_verbose = 0, // verbose turned off ysr@777: stats_verbose, // only prints stats at the end of marking ysr@777: low_verbose, // low verbose, mostly per region and per major event ysr@777: medium_verbose, // a bit more detailed than low ysr@777: high_verbose // per object verbose ysr@777: } CMVerboseLevel; ysr@777: ysr@777: ysr@777: class ConcurrentMarkThread; ysr@777: apetrusenko@984: class ConcurrentMark: public CHeapObj { ysr@777: friend class ConcurrentMarkThread; ysr@777: friend class CMTask; ysr@777: friend class CMBitMapClosure; ysr@777: friend class CSMarkOopClosure; ysr@777: friend class CMGlobalObjectClosure; ysr@777: friend class CMRemarkTask; ysr@777: friend class CMConcurrentMarkingTask; ysr@777: friend class G1ParNoteEndTask; ysr@777: friend class CalcLiveObjectsClosure; ysr@777: ysr@777: protected: ysr@777: ConcurrentMarkThread* _cmThread; // the thread doing the work ysr@777: G1CollectedHeap* _g1h; // the heap. ysr@777: size_t _parallel_marking_threads; // the number of marking ysr@777: // threads we'll use ysr@777: double _sleep_factor; // how much we have to sleep, with ysr@777: // respect to the work we just did, to ysr@777: // meet the marking overhead goal ysr@777: double _marking_task_overhead; // marking target overhead for ysr@777: // a single task ysr@777: ysr@777: // same as the two above, but for the cleanup task ysr@777: double _cleanup_sleep_factor; ysr@777: double _cleanup_task_overhead; ysr@777: ysr@777: // Stuff related to age cohort processing. ysr@777: struct ParCleanupThreadState { ysr@777: char _pre[64]; ysr@777: UncleanRegionList list; ysr@777: char _post[64]; ysr@777: }; ysr@777: ParCleanupThreadState** _par_cleanup_thread_state; ysr@777: ysr@777: // CMS marking support structures ysr@777: CMBitMap _markBitMap1; ysr@777: CMBitMap _markBitMap2; ysr@777: CMBitMapRO* _prevMarkBitMap; // completed mark bitmap ysr@777: CMBitMap* _nextMarkBitMap; // under-construction mark bitmap ysr@777: bool _at_least_one_mark_complete; ysr@777: ysr@777: BitMap _region_bm; ysr@777: BitMap _card_bm; ysr@777: ysr@777: // Heap bounds ysr@777: HeapWord* _heap_start; ysr@777: HeapWord* _heap_end; ysr@777: ysr@777: // For gray objects ysr@777: CMMarkStack _markStack; // Grey objects behind global finger. ysr@777: CMRegionStack _regionStack; // Grey regions behind global finger. ysr@777: HeapWord* volatile _finger; // the global finger, region aligned, ysr@777: // always points to the end of the ysr@777: // last claimed region ysr@777: ysr@777: // marking tasks ysr@777: size_t _max_task_num; // maximum task number ysr@777: size_t _active_tasks; // task num currently active ysr@777: CMTask** _tasks; // task queue array (max_task_num len) ysr@777: CMTaskQueueSet* _task_queues; // task queue set ysr@777: ParallelTaskTerminator _terminator; // for termination ysr@777: ysr@777: // Two sync barriers that are used to synchronise tasks when an ysr@777: // overflow occurs. The algorithm is the following. All tasks enter ysr@777: // the first one to ensure that they have all stopped manipulating ysr@777: // the global data structures. After they exit it, they re-initialise ysr@777: // their data structures and task 0 re-initialises the global data ysr@777: // structures. Then, they enter the second sync barrier. This ysr@777: // ensure, that no task starts doing work before all data ysr@777: // structures (local and global) have been re-initialised. When they ysr@777: // exit it, they are free to start working again. ysr@777: WorkGangBarrierSync _first_overflow_barrier_sync; ysr@777: WorkGangBarrierSync _second_overflow_barrier_sync; ysr@777: ysr@777: ysr@777: // this is set by any task, when an overflow on the global data ysr@777: // structures is detected. ysr@777: volatile bool _has_overflown; ysr@777: // true: marking is concurrent, false: we're in remark ysr@777: volatile bool _concurrent; ysr@777: // set at the end of a Full GC so that marking aborts ysr@777: volatile bool _has_aborted; ysr@777: // used when remark aborts due to an overflow to indicate that ysr@777: // another concurrent marking phase should start ysr@777: volatile bool _restart_for_overflow; ysr@777: ysr@777: // This is true from the very start of concurrent marking until the ysr@777: // point when all the tasks complete their work. It is really used ysr@777: // to determine the points between the end of concurrent marking and ysr@777: // time of remark. ysr@777: volatile bool _concurrent_marking_in_progress; ysr@777: ysr@777: // verbose level ysr@777: CMVerboseLevel _verbose_level; ysr@777: ysr@777: // These two fields are used to implement the optimisation that ysr@777: // avoids pushing objects on the global/region stack if there are ysr@777: // no collection set regions above the lowest finger. ysr@777: ysr@777: // This is the lowest finger (among the global and local fingers), ysr@777: // which is calculated before a new collection set is chosen. ysr@777: HeapWord* _min_finger; ysr@777: // If this flag is true, objects/regions that are marked below the ysr@777: // finger should be pushed on the stack(s). If this is flag is ysr@777: // false, it is safe not to push them on the stack(s). ysr@777: bool _should_gray_objects; ysr@777: ysr@777: // All of these times are in ms. ysr@777: NumberSeq _init_times; ysr@777: NumberSeq _remark_times; ysr@777: NumberSeq _remark_mark_times; ysr@777: NumberSeq _remark_weak_ref_times; ysr@777: NumberSeq _cleanup_times; ysr@777: double _total_counting_time; ysr@777: double _total_rs_scrub_time; ysr@777: ysr@777: double* _accum_task_vtime; // accumulated task vtime ysr@777: ysr@777: WorkGang* _parallel_workers; ysr@777: ysr@777: void weakRefsWork(bool clear_all_soft_refs); ysr@777: ysr@777: void swapMarkBitMaps(); ysr@777: ysr@777: // It resets the global marking data structures, as well as the ysr@777: // task local ones; should be called during initial mark. ysr@777: void reset(); ysr@777: // It resets all the marking data structures. ysr@777: void clear_marking_state(); ysr@777: ysr@777: // It should be called to indicate which phase we're in (concurrent ysr@777: // mark or remark) and how many threads are currently active. ysr@777: void set_phase(size_t active_tasks, bool concurrent); ysr@777: // We do this after we're done with marking so that the marking data ysr@777: // structures are initialised to a sensible and predictable state. ysr@777: void set_non_marking_state(); ysr@777: ysr@777: // prints all gathered CM-related statistics ysr@777: void print_stats(); ysr@777: ysr@777: // accessor methods ysr@777: size_t parallel_marking_threads() { return _parallel_marking_threads; } ysr@777: double sleep_factor() { return _sleep_factor; } ysr@777: double marking_task_overhead() { return _marking_task_overhead;} ysr@777: double cleanup_sleep_factor() { return _cleanup_sleep_factor; } ysr@777: double cleanup_task_overhead() { return _cleanup_task_overhead;} ysr@777: ysr@777: HeapWord* finger() { return _finger; } ysr@777: bool concurrent() { return _concurrent; } ysr@777: size_t active_tasks() { return _active_tasks; } ysr@777: ParallelTaskTerminator* terminator() { return &_terminator; } ysr@777: ysr@777: // It claims the next available region to be scanned by a marking ysr@777: // task. It might return NULL if the next region is empty or we have ysr@777: // run out of regions. In the latter case, out_of_regions() ysr@777: // determines whether we've really run out of regions or the task ysr@777: // should call claim_region() again. This might seem a bit ysr@777: // awkward. Originally, the code was written so that claim_region() ysr@777: // either successfully returned with a non-empty region or there ysr@777: // were no more regions to be claimed. The problem with this was ysr@777: // that, in certain circumstances, it iterated over large chunks of ysr@777: // the heap finding only empty regions and, while it was working, it ysr@777: // was preventing the calling task to call its regular clock ysr@777: // method. So, this way, each task will spend very little time in ysr@777: // claim_region() and is allowed to call the regular clock method ysr@777: // frequently. ysr@777: HeapRegion* claim_region(int task); ysr@777: ysr@777: // It determines whether we've run out of regions to scan. ysr@777: bool out_of_regions() { return _finger == _heap_end; } ysr@777: ysr@777: // Returns the task with the given id ysr@777: CMTask* task(int id) { ysr@777: guarantee( 0 <= id && id < (int) _active_tasks, "task id not within " ysr@777: "active bounds" ); ysr@777: return _tasks[id]; ysr@777: } ysr@777: ysr@777: // Returns the task queue with the given id ysr@777: CMTaskQueue* task_queue(int id) { ysr@777: guarantee( 0 <= id && id < (int) _active_tasks, "task queue id not within " ysr@777: "active bounds" ); ysr@777: return (CMTaskQueue*) _task_queues->queue(id); ysr@777: } ysr@777: ysr@777: // Returns the task queue set ysr@777: CMTaskQueueSet* task_queues() { return _task_queues; } ysr@777: ysr@777: // Access / manipulation of the overflow flag which is set to ysr@777: // indicate that the global stack or region stack has overflown ysr@777: bool has_overflown() { return _has_overflown; } ysr@777: void set_has_overflown() { _has_overflown = true; } ysr@777: void clear_has_overflown() { _has_overflown = false; } ysr@777: ysr@777: bool has_aborted() { return _has_aborted; } ysr@777: bool restart_for_overflow() { return _restart_for_overflow; } ysr@777: ysr@777: // Methods to enter the two overflow sync barriers ysr@777: void enter_first_sync_barrier(int task_num); ysr@777: void enter_second_sync_barrier(int task_num); ysr@777: ysr@777: public: ysr@777: // Manipulation of the global mark stack. ysr@777: // Notice that the first mark_stack_push is CAS-based, whereas the ysr@777: // two below are Mutex-based. This is OK since the first one is only ysr@777: // called during evacuation pauses and doesn't compete with the ysr@777: // other two (which are called by the marking tasks during ysr@777: // concurrent marking or remark). ysr@777: bool mark_stack_push(oop p) { ysr@777: _markStack.par_push(p); ysr@777: if (_markStack.overflow()) { ysr@777: set_has_overflown(); ysr@777: return false; ysr@777: } ysr@777: return true; ysr@777: } ysr@777: bool mark_stack_push(oop* arr, int n) { ysr@777: _markStack.par_push_arr(arr, n); ysr@777: if (_markStack.overflow()) { ysr@777: set_has_overflown(); ysr@777: return false; ysr@777: } ysr@777: return true; ysr@777: } ysr@777: void mark_stack_pop(oop* arr, int max, int* n) { ysr@777: _markStack.par_pop_arr(arr, max, n); ysr@777: } ysr@777: size_t mark_stack_size() { return _markStack.size(); } ysr@777: size_t partial_mark_stack_size_target() { return _markStack.maxElems()/3; } ysr@777: bool mark_stack_overflow() { return _markStack.overflow(); } ysr@777: bool mark_stack_empty() { return _markStack.isEmpty(); } ysr@777: ysr@777: // Manipulation of the region stack ysr@777: bool region_stack_push(MemRegion mr) { ysr@777: _regionStack.push(mr); ysr@777: if (_regionStack.overflow()) { ysr@777: set_has_overflown(); ysr@777: return false; ysr@777: } ysr@777: return true; ysr@777: } ysr@777: MemRegion region_stack_pop() { return _regionStack.pop(); } ysr@777: int region_stack_size() { return _regionStack.size(); } ysr@777: bool region_stack_overflow() { return _regionStack.overflow(); } ysr@777: bool region_stack_empty() { return _regionStack.isEmpty(); } ysr@777: ysr@777: bool concurrent_marking_in_progress() { ysr@777: return _concurrent_marking_in_progress; ysr@777: } ysr@777: void set_concurrent_marking_in_progress() { ysr@777: _concurrent_marking_in_progress = true; ysr@777: } ysr@777: void clear_concurrent_marking_in_progress() { ysr@777: _concurrent_marking_in_progress = false; ysr@777: } ysr@777: ysr@777: void update_accum_task_vtime(int i, double vtime) { ysr@777: _accum_task_vtime[i] += vtime; ysr@777: } ysr@777: ysr@777: double all_task_accum_vtime() { ysr@777: double ret = 0.0; ysr@777: for (int i = 0; i < (int)_max_task_num; ++i) ysr@777: ret += _accum_task_vtime[i]; ysr@777: return ret; ysr@777: } ysr@777: ysr@777: // Attempts to steal an object from the task queues of other tasks ysr@777: bool try_stealing(int task_num, int* hash_seed, oop& obj) { ysr@777: return _task_queues->steal(task_num, hash_seed, obj); ysr@777: } ysr@777: ysr@777: // It grays an object by first marking it. Then, if it's behind the ysr@777: // global finger, it also pushes it on the global stack. ysr@777: void deal_with_reference(oop obj); ysr@777: ysr@777: ConcurrentMark(ReservedSpace rs, int max_regions); ysr@777: ~ConcurrentMark(); ysr@777: ConcurrentMarkThread* cmThread() { return _cmThread; } ysr@777: ysr@777: CMBitMapRO* prevMarkBitMap() const { return _prevMarkBitMap; } ysr@777: CMBitMap* nextMarkBitMap() const { return _nextMarkBitMap; } ysr@777: ysr@777: // The following three are interaction between CM and ysr@777: // G1CollectedHeap ysr@777: ysr@777: // This notifies CM that a root during initial-mark needs to be ysr@777: // grayed and it's MT-safe. Currently, we just mark it. But, in the ysr@777: // future, we can experiment with pushing it on the stack and we can ysr@777: // do this without changing G1CollectedHeap. ysr@777: void grayRoot(oop p); ysr@777: // It's used during evacuation pauses to gray a region, if ysr@777: // necessary, and it's MT-safe. It assumes that the caller has ysr@777: // marked any objects on that region. If _should_gray_objects is ysr@777: // true and we're still doing concurrent marking, the region is ysr@777: // pushed on the region stack, if it is located below the global ysr@777: // finger, otherwise we do nothing. ysr@777: void grayRegionIfNecessary(MemRegion mr); ysr@777: // It's used during evacuation pauses to mark and, if necessary, ysr@777: // gray a single object and it's MT-safe. It assumes the caller did ysr@777: // not mark the object. If _should_gray_objects is true and we're ysr@777: // still doing concurrent marking, the objects is pushed on the ysr@777: // global stack, if it is located below the global finger, otherwise ysr@777: // we do nothing. ysr@777: void markAndGrayObjectIfNecessary(oop p); ysr@777: ysr@777: // This iterates over the bitmap of the previous marking and prints ysr@777: // out all objects that are marked on the bitmap and indicates ysr@777: // whether what they point to is also marked or not. ysr@777: void print_prev_bitmap_reachable(); ysr@777: ysr@777: // Clear the next marking bitmap (will be called concurrently). ysr@777: void clearNextBitmap(); ysr@777: ysr@777: // main CMS steps and related support ysr@777: void checkpointRootsInitial(); ysr@777: ysr@777: // These two do the work that needs to be done before and after the ysr@777: // initial root checkpoint. Since this checkpoint can be done at two ysr@777: // different points (i.e. an explicit pause or piggy-backed on a ysr@777: // young collection), then it's nice to be able to easily share the ysr@777: // pre/post code. It might be the case that we can put everything in ysr@777: // the post method. TP ysr@777: void checkpointRootsInitialPre(); ysr@777: void checkpointRootsInitialPost(); ysr@777: ysr@777: // Do concurrent phase of marking, to a tentative transitive closure. ysr@777: void markFromRoots(); ysr@777: ysr@777: // Process all unprocessed SATB buffers. It is called at the ysr@777: // beginning of an evacuation pause. ysr@777: void drainAllSATBBuffers(); ysr@777: ysr@777: void checkpointRootsFinal(bool clear_all_soft_refs); ysr@777: void checkpointRootsFinalWork(); ysr@777: void calcDesiredRegions(); ysr@777: void cleanup(); ysr@777: void completeCleanup(); ysr@777: ysr@777: // Mark in the previous bitmap. NB: this is usually read-only, so use ysr@777: // this carefully! ysr@777: void markPrev(oop p); ysr@777: void clear(oop p); ysr@777: // Clears marks for all objects in the given range, for both prev and ysr@777: // next bitmaps. NB: the previous bitmap is usually read-only, so use ysr@777: // this carefully! ysr@777: void clearRangeBothMaps(MemRegion mr); ysr@777: ysr@777: // Record the current top of the mark and region stacks; a ysr@777: // subsequent oops_do() on the mark stack and ysr@777: // invalidate_entries_into_cset() on the region stack will iterate ysr@777: // only over indices valid at the time of this call. ysr@777: void set_oops_do_bound() { ysr@777: _markStack.set_oops_do_bound(); ysr@777: _regionStack.set_oops_do_bound(); ysr@777: } ysr@777: // Iterate over the oops in the mark stack and all local queues. It ysr@777: // also calls invalidate_entries_into_cset() on the region stack. ysr@777: void oops_do(OopClosure* f); ysr@777: // It is called at the end of an evacuation pause during marking so ysr@777: // that CM is notified of where the new end of the heap is. It ysr@777: // doesn't do anything if concurrent_marking_in_progress() is false, ysr@777: // unless the force parameter is true. ysr@777: void update_g1_committed(bool force = false); ysr@777: ysr@777: void complete_marking_in_collection_set(); ysr@777: ysr@777: // It indicates that a new collection set is being chosen. ysr@777: void newCSet(); ysr@777: // It registers a collection set heap region with CM. This is used ysr@777: // to determine whether any heap regions are located above the finger. ysr@777: void registerCSetRegion(HeapRegion* hr); ysr@777: ysr@777: // Returns "true" if at least one mark has been completed. ysr@777: bool at_least_one_mark_complete() { return _at_least_one_mark_complete; } ysr@777: ysr@777: bool isMarked(oop p) const { ysr@777: assert(p != NULL && p->is_oop(), "expected an oop"); ysr@777: HeapWord* addr = (HeapWord*)p; ysr@777: assert(addr >= _nextMarkBitMap->startWord() || ysr@777: addr < _nextMarkBitMap->endWord(), "in a region"); ysr@777: ysr@777: return _nextMarkBitMap->isMarked(addr); ysr@777: } ysr@777: ysr@777: inline bool not_yet_marked(oop p) const; ysr@777: ysr@777: // XXX Debug code ysr@777: bool containing_card_is_marked(void* p); ysr@777: bool containing_cards_are_marked(void* start, void* last); ysr@777: ysr@777: bool isPrevMarked(oop p) const { ysr@777: assert(p != NULL && p->is_oop(), "expected an oop"); ysr@777: HeapWord* addr = (HeapWord*)p; ysr@777: assert(addr >= _prevMarkBitMap->startWord() || ysr@777: addr < _prevMarkBitMap->endWord(), "in a region"); ysr@777: ysr@777: return _prevMarkBitMap->isMarked(addr); ysr@777: } ysr@777: ysr@777: inline bool do_yield_check(int worker_i = 0); ysr@777: inline bool should_yield(); ysr@777: ysr@777: // Called to abort the marking cycle after a Full GC takes palce. ysr@777: void abort(); ysr@777: ysr@777: // This prints the global/local fingers. It is used for debugging. ysr@777: NOT_PRODUCT(void print_finger();) ysr@777: ysr@777: void print_summary_info(); ysr@777: ysr@777: // The following indicate whether a given verbose level has been ysr@777: // set. Notice that anything above stats is conditional to ysr@777: // _MARKING_VERBOSE_ having been set to 1 ysr@777: bool verbose_stats() ysr@777: { return _verbose_level >= stats_verbose; } ysr@777: bool verbose_low() ysr@777: { return _MARKING_VERBOSE_ && _verbose_level >= low_verbose; } ysr@777: bool verbose_medium() ysr@777: { return _MARKING_VERBOSE_ && _verbose_level >= medium_verbose; } ysr@777: bool verbose_high() ysr@777: { return _MARKING_VERBOSE_ && _verbose_level >= high_verbose; } ysr@777: }; ysr@777: ysr@777: // A class representing a marking task. ysr@777: class CMTask : public TerminatorTerminator { ysr@777: private: ysr@777: enum PrivateConstants { ysr@777: // the regular clock call is called once the scanned words reaches ysr@777: // this limit ysr@777: words_scanned_period = 12*1024, ysr@777: // the regular clock call is called once the number of visited ysr@777: // references reaches this limit ysr@777: refs_reached_period = 384, ysr@777: // initial value for the hash seed, used in the work stealing code ysr@777: init_hash_seed = 17, ysr@777: // how many entries will be transferred between global stack and ysr@777: // local queues ysr@777: global_stack_transfer_size = 16 ysr@777: }; ysr@777: ysr@777: int _task_id; ysr@777: G1CollectedHeap* _g1h; ysr@777: ConcurrentMark* _cm; ysr@777: CMBitMap* _nextMarkBitMap; ysr@777: // the task queue of this task ysr@777: CMTaskQueue* _task_queue; ysr@1280: private: ysr@777: // the task queue set---needed for stealing ysr@777: CMTaskQueueSet* _task_queues; ysr@777: // indicates whether the task has been claimed---this is only for ysr@777: // debugging purposes ysr@777: bool _claimed; ysr@777: ysr@777: // number of calls to this task ysr@777: int _calls; ysr@777: ysr@777: // when the virtual timer reaches this time, the marking step should ysr@777: // exit ysr@777: double _time_target_ms; ysr@777: // the start time of the current marking step ysr@777: double _start_time_ms; ysr@777: ysr@777: // the oop closure used for iterations over oops ysr@777: OopClosure* _oop_closure; ysr@777: ysr@777: // the region this task is scanning, NULL if we're not scanning any ysr@777: HeapRegion* _curr_region; ysr@777: // the local finger of this task, NULL if we're not scanning a region ysr@777: HeapWord* _finger; ysr@777: // limit of the region this task is scanning, NULL if we're not scanning one ysr@777: HeapWord* _region_limit; ysr@777: ysr@777: // This is used only when we scan regions popped from the region ysr@777: // stack. It records what the last object on such a region we ysr@777: // scanned was. It is used to ensure that, if we abort region ysr@777: // iteration, we do not rescan the first part of the region. This ysr@777: // should be NULL when we're not scanning a region from the region ysr@777: // stack. ysr@777: HeapWord* _region_finger; ysr@777: ysr@777: // the number of words this task has scanned ysr@777: size_t _words_scanned; ysr@777: // When _words_scanned reaches this limit, the regular clock is ysr@777: // called. Notice that this might be decreased under certain ysr@777: // circumstances (i.e. when we believe that we did an expensive ysr@777: // operation). ysr@777: size_t _words_scanned_limit; ysr@777: // the initial value of _words_scanned_limit (i.e. what it was ysr@777: // before it was decreased). ysr@777: size_t _real_words_scanned_limit; ysr@777: ysr@777: // the number of references this task has visited ysr@777: size_t _refs_reached; ysr@777: // When _refs_reached reaches this limit, the regular clock is ysr@777: // called. Notice this this might be decreased under certain ysr@777: // circumstances (i.e. when we believe that we did an expensive ysr@777: // operation). ysr@777: size_t _refs_reached_limit; ysr@777: // the initial value of _refs_reached_limit (i.e. what it was before ysr@777: // it was decreased). ysr@777: size_t _real_refs_reached_limit; ysr@777: ysr@777: // used by the work stealing stuff ysr@777: int _hash_seed; ysr@777: // if this is true, then the task has aborted for some reason ysr@777: bool _has_aborted; ysr@777: // set when the task aborts because it has met its time quota ysr@777: bool _has_aborted_timed_out; ysr@777: // true when we're draining SATB buffers; this avoids the task ysr@777: // aborting due to SATB buffers being available (as we're already ysr@777: // dealing with them) ysr@777: bool _draining_satb_buffers; ysr@777: ysr@777: // number sequence of past step times ysr@777: NumberSeq _step_times_ms; ysr@777: // elapsed time of this task ysr@777: double _elapsed_time_ms; ysr@777: // termination time of this task ysr@777: double _termination_time_ms; ysr@777: // when this task got into the termination protocol ysr@777: double _termination_start_time_ms; ysr@777: ysr@777: // true when the task is during a concurrent phase, false when it is ysr@777: // in the remark phase (so, in the latter case, we do not have to ysr@777: // check all the things that we have to check during the concurrent ysr@777: // phase, i.e. SATB buffer availability...) ysr@777: bool _concurrent; ysr@777: ysr@777: TruncatedSeq _marking_step_diffs_ms; ysr@777: ysr@777: // LOTS of statistics related with this task ysr@777: #if _MARKING_STATS_ ysr@777: NumberSeq _all_clock_intervals_ms; ysr@777: double _interval_start_time_ms; ysr@777: ysr@777: int _aborted; ysr@777: int _aborted_overflow; ysr@777: int _aborted_cm_aborted; ysr@777: int _aborted_yield; ysr@777: int _aborted_timed_out; ysr@777: int _aborted_satb; ysr@777: int _aborted_termination; ysr@777: ysr@777: int _steal_attempts; ysr@777: int _steals; ysr@777: ysr@777: int _clock_due_to_marking; ysr@777: int _clock_due_to_scanning; ysr@777: ysr@777: int _local_pushes; ysr@777: int _local_pops; ysr@777: int _local_max_size; ysr@777: int _objs_scanned; ysr@777: ysr@777: int _global_pushes; ysr@777: int _global_pops; ysr@777: int _global_max_size; ysr@777: ysr@777: int _global_transfers_to; ysr@777: int _global_transfers_from; ysr@777: ysr@777: int _region_stack_pops; ysr@777: ysr@777: int _regions_claimed; ysr@777: int _objs_found_on_bitmap; ysr@777: ysr@777: int _satb_buffers_processed; ysr@777: #endif // _MARKING_STATS_ ysr@777: ysr@777: // it updates the local fields after this task has claimed ysr@777: // a new region to scan ysr@777: void setup_for_region(HeapRegion* hr); ysr@777: // it brings up-to-date the limit of the region ysr@777: void update_region_limit(); ysr@777: // it resets the local fields after a task has finished scanning a ysr@777: // region ysr@777: void giveup_current_region(); ysr@777: ysr@777: // called when either the words scanned or the refs visited limit ysr@777: // has been reached ysr@777: void reached_limit(); ysr@777: // recalculates the words scanned and refs visited limits ysr@777: void recalculate_limits(); ysr@777: // decreases the words scanned and refs visited limits when we reach ysr@777: // an expensive operation ysr@777: void decrease_limits(); ysr@777: // it checks whether the words scanned or refs visited reached their ysr@777: // respective limit and calls reached_limit() if they have ysr@777: void check_limits() { ysr@777: if (_words_scanned >= _words_scanned_limit || ysr@777: _refs_reached >= _refs_reached_limit) ysr@777: reached_limit(); ysr@777: } ysr@777: // this is supposed to be called regularly during a marking step as ysr@777: // it checks a bunch of conditions that might cause the marking step ysr@777: // to abort ysr@777: void regular_clock_call(); ysr@777: bool concurrent() { return _concurrent; } ysr@777: ysr@777: public: ysr@777: // It resets the task; it should be called right at the beginning of ysr@777: // a marking phase. ysr@777: void reset(CMBitMap* _nextMarkBitMap); ysr@777: // it clears all the fields that correspond to a claimed region. ysr@777: void clear_region_fields(); ysr@777: ysr@777: void set_concurrent(bool concurrent) { _concurrent = concurrent; } ysr@777: ysr@777: // The main method of this class which performs a marking step ysr@777: // trying not to exceed the given duration. However, it might exit ysr@777: // prematurely, according to some conditions (i.e. SATB buffers are ysr@777: // available for processing). ysr@777: void do_marking_step(double target_ms); ysr@777: ysr@777: // These two calls start and stop the timer ysr@777: void record_start_time() { ysr@777: _elapsed_time_ms = os::elapsedTime() * 1000.0; ysr@777: } ysr@777: void record_end_time() { ysr@777: _elapsed_time_ms = os::elapsedTime() * 1000.0 - _elapsed_time_ms; ysr@777: } ysr@777: ysr@777: // returns the task ID ysr@777: int task_id() { return _task_id; } ysr@777: ysr@777: // From TerminatorTerminator. It determines whether this task should ysr@777: // exit the termination protocol after it's entered it. ysr@777: virtual bool should_exit_termination(); ysr@777: ysr@777: HeapWord* finger() { return _finger; } ysr@777: ysr@777: bool has_aborted() { return _has_aborted; } ysr@777: void set_has_aborted() { _has_aborted = true; } ysr@777: void clear_has_aborted() { _has_aborted = false; } ysr@777: bool claimed() { return _claimed; } ysr@777: ysr@777: void set_oop_closure(OopClosure* oop_closure) { ysr@777: _oop_closure = oop_closure; ysr@777: } ysr@777: ysr@777: // It grays the object by marking it and, if necessary, pushing it ysr@777: // on the local queue ysr@777: void deal_with_reference(oop obj); ysr@777: ysr@777: // It scans an object and visits its children. ysr@777: void scan_object(oop obj) { ysr@777: tmp_guarantee_CM( _nextMarkBitMap->isMarked((HeapWord*) obj), ysr@777: "invariant" ); ysr@777: ysr@777: if (_cm->verbose_high()) ysr@777: gclog_or_tty->print_cr("[%d] we're scanning object "PTR_FORMAT, ysr@777: _task_id, (void*) obj); ysr@777: ysr@777: size_t obj_size = obj->size(); ysr@777: _words_scanned += obj_size; ysr@777: ysr@777: obj->oop_iterate(_oop_closure); ysr@777: statsOnly( ++_objs_scanned ); ysr@777: check_limits(); ysr@777: } ysr@777: ysr@777: // It pushes an object on the local queue. ysr@777: void push(oop obj); ysr@777: ysr@777: // These two move entries to/from the global stack. ysr@777: void move_entries_to_global_stack(); ysr@777: void get_entries_from_global_stack(); ysr@777: ysr@777: // It pops and scans objects from the local queue. If partially is ysr@777: // true, then it stops when the queue size is of a given limit. If ysr@777: // partially is false, then it stops when the queue is empty. ysr@777: void drain_local_queue(bool partially); ysr@777: // It moves entries from the global stack to the local queue and ysr@777: // drains the local queue. If partially is true, then it stops when ysr@777: // both the global stack and the local queue reach a given size. If ysr@777: // partially if false, it tries to empty them totally. ysr@777: void drain_global_stack(bool partially); ysr@777: // It keeps picking SATB buffers and processing them until no SATB ysr@777: // buffers are available. ysr@777: void drain_satb_buffers(); ysr@777: // It keeps popping regions from the region stack and processing ysr@777: // them until the region stack is empty. ysr@777: void drain_region_stack(BitMapClosure* closure); ysr@777: ysr@777: // moves the local finger to a new location ysr@777: inline void move_finger_to(HeapWord* new_finger) { ysr@777: tmp_guarantee_CM( new_finger >= _finger && new_finger < _region_limit, ysr@777: "invariant" ); ysr@777: _finger = new_finger; ysr@777: } ysr@777: ysr@777: // moves the region finger to a new location ysr@777: inline void move_region_finger_to(HeapWord* new_finger) { ysr@777: tmp_guarantee_CM( new_finger < _cm->finger(), "invariant" ); ysr@777: _region_finger = new_finger; ysr@777: } ysr@777: ysr@777: CMTask(int task_num, ConcurrentMark *cm, ysr@777: CMTaskQueue* task_queue, CMTaskQueueSet* task_queues); ysr@777: ysr@777: // it prints statistics associated with this task ysr@777: void print_stats(); ysr@777: ysr@777: #if _MARKING_STATS_ ysr@777: void increase_objs_found_on_bitmap() { ++_objs_found_on_bitmap; } ysr@777: #endif // _MARKING_STATS_ ysr@777: };