1/*
2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP
26#define SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP
27
28#include "gc/parallel/cardTableExtension.hpp"
29#include "gc/parallel/parallelScavengeHeap.hpp"
30#include "gc/parallel/psPromotionManager.inline.hpp"
31#include "gc/parallel/psScavenge.hpp"
32#include "logging/log.hpp"
33#include "memory/iterator.hpp"
34#include "memory/resourceArea.hpp"
35#include "utilities/globalDefinitions.hpp"
36
37inline void PSScavenge::save_to_space_top_before_gc() {
38  ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
39  _to_space_top_before_gc = heap->young_gen()->to_space()->top();
40}
41
42template <class T> inline bool PSScavenge::should_scavenge(T* p) {
43  T heap_oop = oopDesc::load_heap_oop(p);
44  return PSScavenge::is_obj_in_young(heap_oop);
45}
46
47template <class T>
48inline bool PSScavenge::should_scavenge(T* p, MutableSpace* to_space) {
49  if (should_scavenge(p)) {
50    oop obj = oopDesc::load_decode_heap_oop_not_null(p);
51    // Skip objects copied to to_space since the scavenge started.
52    HeapWord* const addr = (HeapWord*)obj;
53    return addr < to_space_top_before_gc() || addr >= to_space->end();
54  }
55  return false;
56}
57
58template <class T>
59inline bool PSScavenge::should_scavenge(T* p, bool check_to_space) {
60  if (check_to_space) {
61    ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
62    return should_scavenge(p, heap->young_gen()->to_space());
63  }
64  return should_scavenge(p);
65}
66
67template<bool promote_immediately>
68class PSRootsClosure: public OopClosure {
69 private:
70  PSPromotionManager* _promotion_manager;
71
72 protected:
73  template <class T> void do_oop_work(T *p) {
74    if (PSScavenge::should_scavenge(p)) {
75      // We never card mark roots, maybe call a func without test?
76      _promotion_manager->copy_and_push_safe_barrier<T, promote_immediately>(p);
77    }
78  }
79 public:
80  PSRootsClosure(PSPromotionManager* pm) : _promotion_manager(pm) { }
81  void do_oop(oop* p)       { PSRootsClosure::do_oop_work(p); }
82  void do_oop(narrowOop* p) { PSRootsClosure::do_oop_work(p); }
83};
84
85typedef PSRootsClosure</*promote_immediately=*/false> PSScavengeRootsClosure;
86typedef PSRootsClosure</*promote_immediately=*/true> PSPromoteRootsClosure;
87
88// Scavenges a single oop in a Klass.
89class PSScavengeFromKlassClosure: public OopClosure {
90 private:
91  PSPromotionManager* _pm;
92  // Used to redirty a scanned klass if it has oops
93  // pointing to the young generation after being scanned.
94  Klass*             _scanned_klass;
95 public:
96  PSScavengeFromKlassClosure(PSPromotionManager* pm) : _pm(pm), _scanned_klass(NULL) { }
97  void do_oop(narrowOop* p) { ShouldNotReachHere(); }
98  void do_oop(oop* p)       {
99    ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
100    assert(!psh->is_in_reserved(p), "GC barrier needed");
101    if (PSScavenge::should_scavenge(p)) {
102      assert(PSScavenge::should_scavenge(p, true), "revisiting object?");
103
104      oop o = *p;
105      oop new_obj;
106      if (o->is_forwarded()) {
107        new_obj = o->forwardee();
108      } else {
109        new_obj = _pm->copy_to_survivor_space</*promote_immediately=*/false>(o);
110      }
111      oopDesc::encode_store_heap_oop_not_null(p, new_obj);
112
113      if (PSScavenge::is_obj_in_young(new_obj)) {
114        do_klass_barrier();
115      }
116    }
117  }
118
119  void set_scanned_klass(Klass* klass) {
120    assert(_scanned_klass == NULL || klass == NULL, "Should always only handling one klass at a time");
121    _scanned_klass = klass;
122  }
123
124 private:
125  void do_klass_barrier() {
126    assert(_scanned_klass != NULL, "Should not be called without having a scanned klass");
127    _scanned_klass->record_modified_oops();
128  }
129
130};
131
132// Scavenges the oop in a Klass.
133class PSScavengeKlassClosure: public KlassClosure {
134 private:
135  PSScavengeFromKlassClosure _oop_closure;
136 protected:
137 public:
138  PSScavengeKlassClosure(PSPromotionManager* pm) : _oop_closure(pm) { }
139  void do_klass(Klass* klass) {
140    // If the klass has not been dirtied we know that there's
141    // no references into  the young gen and we can skip it.
142
143    if (klass->has_modified_oops()) {
144      // Clean the klass since we're going to scavenge all the metadata.
145      klass->clear_modified_oops();
146
147      // Setup the promotion manager to redirty this klass
148      // if references are left in the young gen.
149      _oop_closure.set_scanned_klass(klass);
150
151      klass->oops_do(&_oop_closure);
152
153      _oop_closure.set_scanned_klass(NULL);
154    }
155  }
156};
157
158#endif // SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP
159