Mercurial > hg > graal-compiler
diff src/share/vm/gc_implementation/parNew/parNewGeneration.hpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | ba764ed4b6f2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,388 @@ +/* + * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class ChunkArray; +class ParScanWithoutBarrierClosure; +class ParScanWithBarrierClosure; +class ParRootScanWithoutBarrierClosure; +class ParRootScanWithBarrierTwoGensClosure; +class ParEvacuateFollowersClosure; + +// It would be better if these types could be kept local to the .cpp file, +// but they must be here to allow ParScanClosure::do_oop_work to be defined +// in genOopClosures.inline.hpp. + + +typedef OopTaskQueue ObjToScanQueue; +typedef OopTaskQueueSet ObjToScanQueueSet; + +// Enable this to get push/pop/steal stats. +const int PAR_STATS_ENABLED = 0; + +class ParKeepAliveClosure: public DefNewGeneration::KeepAliveClosure { + ParScanWeakRefClosure* _par_cl; + public: + ParKeepAliveClosure(ParScanWeakRefClosure* cl); + void do_oop(oop* p); +}; + +// The state needed by thread performing parallel young-gen collection. +class ParScanThreadState { + friend class ParScanThreadStateSet; + ObjToScanQueue *_work_queue; + + ParGCAllocBuffer _to_space_alloc_buffer; + + ParScanWithoutBarrierClosure _to_space_closure; // scan_without_gc_barrier + ParScanWithBarrierClosure _old_gen_closure; // scan_with_gc_barrier + ParRootScanWithoutBarrierClosure _to_space_root_closure; // scan_root_without_gc_barrier + // One of these two will be passed to process_strong_roots, which will + // set its generation. The first is for two-gen configs where the + // old gen collects the perm gen; the second is for arbitrary configs. + // The second isn't used right now (it used to be used for the train, an + // incremental collector) but the declaration has been left as a reminder. + ParRootScanWithBarrierTwoGensClosure _older_gen_closure; + // This closure will always be bound to the old gen; it will be used + // in evacuate_followers. + ParRootScanWithBarrierTwoGensClosure _old_gen_root_closure; // scan_old_root_with_gc_barrier + ParEvacuateFollowersClosure _evacuate_followers; + DefNewGeneration::IsAliveClosure _is_alive_closure; + ParScanWeakRefClosure _scan_weak_ref_closure; + ParKeepAliveClosure _keep_alive_closure; + + + Space* _to_space; + Space* to_space() { return _to_space; } + + Generation* _old_gen; + Generation* old_gen() { return _old_gen; } + + HeapWord *_young_old_boundary; + + int _hash_seed; + int _thread_num; + ageTable _ageTable; + + bool _to_space_full; + + int _pushes, _pops, _steals, _steal_attempts, _term_attempts; + int _overflow_pushes, _overflow_refills, _overflow_refill_objs; + + // Timing numbers. + double _start; + double _start_strong_roots; + double _strong_roots_time; + double _start_term; + double _term_time; + + // Helper for trim_queues. Scans subset of an array and makes + // remainder available for work stealing. + void scan_partial_array_and_push_remainder(oop obj); + + // In support of CMS' parallel rescan of survivor space. + ChunkArray* _survivor_chunk_array; + ChunkArray* survivor_chunk_array() { return _survivor_chunk_array; } + + void record_survivor_plab(HeapWord* plab_start, size_t plab_word_size); + + ParScanThreadState(Space* to_space_, ParNewGeneration* gen_, + Generation* old_gen_, int thread_num_, + ObjToScanQueueSet* work_queue_set_, size_t desired_plab_sz_, + ParallelTaskTerminator& term_); + +public: + ageTable* age_table() {return &_ageTable;} + + ObjToScanQueue* work_queue() { return _work_queue; } + + ParGCAllocBuffer* to_space_alloc_buffer() { + return &_to_space_alloc_buffer; + } + + ParEvacuateFollowersClosure& evacuate_followers_closure() { return _evacuate_followers; } + DefNewGeneration::IsAliveClosure& is_alive_closure() { return _is_alive_closure; } + ParScanWeakRefClosure& scan_weak_ref_closure() { return _scan_weak_ref_closure; } + ParKeepAliveClosure& keep_alive_closure() { return _keep_alive_closure; } + ParScanClosure& older_gen_closure() { return _older_gen_closure; } + ParRootScanWithoutBarrierClosure& to_space_root_closure() { return _to_space_root_closure; }; + + // Decrease queue size below "max_size". + void trim_queues(int max_size); + + // Is new_obj a candidate for scan_partial_array_and_push_remainder method. + inline bool should_be_partially_scanned(oop new_obj, oop old_obj) const; + + int* hash_seed() { return &_hash_seed; } + int thread_num() { return _thread_num; } + + // Allocate a to-space block of size "sz", or else return NULL. + HeapWord* alloc_in_to_space_slow(size_t word_sz); + + HeapWord* alloc_in_to_space(size_t word_sz) { + HeapWord* obj = to_space_alloc_buffer()->allocate(word_sz); + if (obj != NULL) return obj; + else return alloc_in_to_space_slow(word_sz); + } + + HeapWord* young_old_boundary() { return _young_old_boundary; } + + void set_young_old_boundary(HeapWord *boundary) { + _young_old_boundary = boundary; + } + + // Undo the most recent allocation ("obj", of "word_sz"). + void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz); + + int pushes() { return _pushes; } + int pops() { return _pops; } + int steals() { return _steals; } + int steal_attempts() { return _steal_attempts; } + int term_attempts() { return _term_attempts; } + int overflow_pushes() { return _overflow_pushes; } + int overflow_refills() { return _overflow_refills; } + int overflow_refill_objs() { return _overflow_refill_objs; } + + void note_push() { if (PAR_STATS_ENABLED) _pushes++; } + void note_pop() { if (PAR_STATS_ENABLED) _pops++; } + void note_steal() { if (PAR_STATS_ENABLED) _steals++; } + void note_steal_attempt() { if (PAR_STATS_ENABLED) _steal_attempts++; } + void note_term_attempt() { if (PAR_STATS_ENABLED) _term_attempts++; } + void note_overflow_push() { if (PAR_STATS_ENABLED) _overflow_pushes++; } + void note_overflow_refill(int objs) { + if (PAR_STATS_ENABLED) { + _overflow_refills++; + _overflow_refill_objs += objs; + } + } + + void start_strong_roots() { + _start_strong_roots = os::elapsedTime(); + } + void end_strong_roots() { + _strong_roots_time += (os::elapsedTime() - _start_strong_roots); + } + double strong_roots_time() { return _strong_roots_time; } + void start_term_time() { + note_term_attempt(); + _start_term = os::elapsedTime(); + } + void end_term_time() { + _term_time += (os::elapsedTime() - _start_term); + } + double term_time() { return _term_time; } + + double elapsed() { + return os::elapsedTime() - _start; + } + +}; + +class ParNewGenTask: public AbstractGangTask { + ParNewGeneration* _gen; + Generation* _next_gen; + HeapWord* _young_old_boundary; + class ParScanThreadStateSet* _state_set; + +public: + ParNewGenTask(ParNewGeneration* gen, + Generation* next_gen, + HeapWord* young_old_boundary, + ParScanThreadStateSet* state_set); + + HeapWord* young_old_boundary() { return _young_old_boundary; } + + void work(int i); +}; + +class KeepAliveClosure: public DefNewGeneration::KeepAliveClosure { + public: + KeepAliveClosure(ScanWeakRefClosure* cl); + void do_oop(oop* p); +}; + +class EvacuateFollowersClosureGeneral: public VoidClosure { + GenCollectedHeap* _gch; + int _level; + OopsInGenClosure* _scan_cur_or_nonheap; + OopsInGenClosure* _scan_older; + public: + EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, int level, + OopsInGenClosure* cur, + OopsInGenClosure* older); + void do_void(); +}; + +// Closure for scanning ParNewGeneration. +// Same as ScanClosure, except does parallel GC barrier. +class ScanClosureWithParBarrier: public ScanClosure { +public: + ScanClosureWithParBarrier(ParNewGeneration* g, bool gc_barrier); + void do_oop(oop* p); +}; + +// Implements AbstractRefProcTaskExecutor for ParNew. +class ParNewRefProcTaskExecutor: public AbstractRefProcTaskExecutor { +public: + + ParNewRefProcTaskExecutor(ParNewGeneration& generation, + ParScanThreadStateSet& state_set) + : _generation(generation), _state_set(state_set) + { } + + // Executes a task using worker threads. + virtual void execute(ProcessTask& task); + virtual void execute(EnqueueTask& task); + // Switch to single threaded mode. + virtual void set_single_threaded_mode(); +private: + ParNewGeneration& _generation; + ParScanThreadStateSet& _state_set; +}; + + +// A Generation that does parallel young-gen collection. + +class ParNewGeneration: public DefNewGeneration { + friend class ParNewGenTask; + friend class ParNewRefProcTask; + friend class ParNewRefProcTaskExecutor; + friend class ParScanThreadStateSet; + + // XXX use a global constant instead of 64! + struct ObjToScanQueuePadded { + ObjToScanQueue work_queue; + char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing + }; + + // The per-thread work queues, available here for stealing. + ObjToScanQueueSet* _task_queues; + + // Desired size of survivor space plab's + PLABStats _plab_stats; + + // A list of from-space images of to-be-scanned objects, threaded through + // klass-pointers (klass information already copied to the forwarded + // image.) Manipulated with CAS. + oop _overflow_list; + + // If true, older generation does not support promotion undo, so avoid. + static bool _avoid_promotion_undo; + + // This closure is used by the reference processor to filter out + // references to live referent. + DefNewGeneration::IsAliveClosure _is_alive_closure; + + static oop real_forwardee_slow(oop obj); + static void waste_some_time(); + + // Preserve the mark of "obj", if necessary, in preparation for its mark + // word being overwritten with a self-forwarding-pointer. + void preserve_mark_if_necessary(oop obj, markOop m); + + protected: + + bool _survivor_overflow; + + bool avoid_promotion_undo() { return _avoid_promotion_undo; } + void set_avoid_promotion_undo(bool v) { _avoid_promotion_undo = v; } + + bool survivor_overflow() { return _survivor_overflow; } + void set_survivor_overflow(bool v) { _survivor_overflow = v; } + + // Adjust the tenuring threshold. See the implementation for + // the details of the policy. + virtual void adjust_desired_tenuring_threshold(); + +public: + ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level); + + ~ParNewGeneration() { + for (uint i = 0; i < ParallelGCThreads; i++) + delete _task_queues->queue(i); + + delete _task_queues; + } + + virtual void ref_processor_init(); + virtual Generation::Name kind() { return Generation::ParNew; } + virtual const char* name() const; + virtual const char* short_name() const { return "ParNew"; } + + // override + virtual bool refs_discovery_is_mt() const { + assert(UseParNewGC, "ParNewGeneration only when UseParNewGC"); + return ParallelGCThreads > 1; + } + + // Make the collection virtual. + virtual void collect(bool full, + bool clear_all_soft_refs, + size_t size, + bool is_tlab); + + // This needs to be visible to the closure function. + // "obj" is the object to be copied, "m" is a recent value of its mark + // that must not contain a forwarding pointer (though one might be + // inserted in "obj"s mark word by a parallel thread). + inline oop copy_to_survivor_space(ParScanThreadState* par_scan_state, + oop obj, size_t obj_sz, markOop m) { + if (_avoid_promotion_undo) { + return copy_to_survivor_space_avoiding_promotion_undo(par_scan_state, + obj, obj_sz, m); + } + + return copy_to_survivor_space_with_undo(par_scan_state, obj, obj_sz, m); + } + + oop copy_to_survivor_space_avoiding_promotion_undo(ParScanThreadState* par_scan_state, + oop obj, size_t obj_sz, markOop m); + + oop copy_to_survivor_space_with_undo(ParScanThreadState* par_scan_state, + oop obj, size_t obj_sz, markOop m); + + // Push the given (from-space) object on the global overflow list. + void push_on_overflow_list(oop from_space_obj); + + // If the global overflow list is non-empty, move some tasks from it + // onto "work_q" (which must be empty). No more than 1/4 of the + // max_elems of "work_q" are moved. + bool take_from_overflow_list(ParScanThreadState* par_scan_state); + + // The task queues to be used by parallel GC threads. + ObjToScanQueueSet* task_queues() { + return _task_queues; + } + + PLABStats* plab_stats() { + return &_plab_stats; + } + + size_t desired_plab_sz() { + return _plab_stats.desired_plab_sz(); + } + + static oop real_forwardee(oop obj); + + DEBUG_ONLY(static bool is_legal_forward_ptr(oop p);) +};