1 /*
   2  * Copyright (c) 2003, 2019, 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 #include "precompiled.hpp"
  26 #include "gc/parallel/psVirtualspace.hpp"
  27 #include "memory/virtualspace.hpp"
  28 #include "runtime/os.hpp"
  29 
  30 // PSVirtualSpace
  31 
  32 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) :
  33   _alignment(alignment)
  34 {
  35   set_reserved(rs);
  36   set_committed(reserved_low_addr(), reserved_low_addr());
  37   DEBUG_ONLY(verify());
  38 }
  39 
  40 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) :
  41   _alignment(os::vm_page_size())
  42 {
  43   set_reserved(rs);
  44   set_committed(reserved_low_addr(), reserved_low_addr());
  45   DEBUG_ONLY(verify());
  46 }
  47 
  48 // Deprecated.
  49 PSVirtualSpace::PSVirtualSpace():
  50   _alignment(os::vm_page_size()),
  51   _reserved_low_addr(NULL),
  52   _reserved_high_addr(NULL),
  53   _committed_low_addr(NULL),
  54   _committed_high_addr(NULL),
  55   _special(false) {
  56 }
  57 
  58 // Deprecated.
  59 bool PSVirtualSpace::initialize(ReservedSpace rs,
  60                                 size_t commit_size) {
  61   set_reserved(rs);
  62   set_committed(reserved_low_addr(), reserved_low_addr());
  63 
  64   // Commit to initial size.
  65   assert(commit_size <= rs.size(), "commit_size too big");
  66   bool result = commit_size > 0 ? expand_by(commit_size) : true;
  67   DEBUG_ONLY(verify());
  68   return result;
  69 }
  70 
  71 PSVirtualSpace::~PSVirtualSpace() {
  72   release();
  73 }
  74 
  75 bool PSVirtualSpace::contains(void* p) const {
  76   char* const cp = (char*)p;
  77   return cp >= committed_low_addr() && cp < committed_high_addr();
  78 }
  79 
  80 void PSVirtualSpace::release() {
  81   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
  82   // This may not release memory it didn't reserve.
  83   // Use rs.release() to release the underlying memory instead.
  84   _reserved_low_addr = _reserved_high_addr = NULL;
  85   _committed_low_addr = _committed_high_addr = NULL;
  86   _special = false;
  87 }
  88 
  89 bool PSVirtualSpace::expand_by(size_t bytes) {
  90   assert(is_aligned(bytes), "arg not aligned");
  91   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
  92 
  93   if (uncommitted_size() < bytes) {
  94     return false;
  95   }
  96 
  97   char* const base_addr = committed_high_addr();
  98   bool result = special() ||
  99          os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
 100   if (result) {
 101     _committed_high_addr += bytes;
 102   }
 103 
 104   return result;
 105 }
 106 
 107 bool PSVirtualSpace::shrink_by(size_t bytes) {
 108   assert(is_aligned(bytes), "arg not aligned");
 109   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 110 
 111   if (committed_size() < bytes) {
 112     return false;
 113   }
 114 
 115   char* const base_addr = committed_high_addr() - bytes;
 116   bool result = special() || os::uncommit_memory(base_addr, bytes, !ExecMem);
 117   if (result) {
 118     _committed_high_addr -= bytes;
 119   }
 120 
 121   return result;
 122 }
 123 
 124 size_t
 125 PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) {
 126   assert(is_aligned(bytes), "arg not aligned");
 127   assert(grows_up(), "this space must grow up");
 128   assert(other_space->grows_down(), "other space must grow down");
 129   assert(reserved_high_addr() == other_space->reserved_low_addr(),
 130          "spaces not contiguous");
 131   assert(special() == other_space->special(), "one space is special, the other is not");
 132   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 133   DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
 134 
 135   size_t bytes_needed = bytes;
 136 
 137   // First use the uncommitted region in this space.
 138   size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
 139   if (tmp_bytes > 0) {
 140     if (expand_by(tmp_bytes)) {
 141       bytes_needed -= tmp_bytes;
 142     } else {
 143       return 0;
 144     }
 145   }
 146 
 147   // Next take from the uncommitted region in the other space, and commit it.
 148   tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
 149   if (tmp_bytes > 0) {
 150     char* const commit_base = committed_high_addr();
 151     if (other_space->special() ||
 152         os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) {
 153       // Reduce the reserved region in the other space.
 154       other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 155                                 other_space->reserved_high_addr(),
 156                                 other_space->special());
 157 
 158       // Grow both reserved and committed in this space.
 159       _reserved_high_addr += tmp_bytes;
 160       _committed_high_addr += tmp_bytes;
 161       bytes_needed -= tmp_bytes;
 162     } else {
 163       return bytes - bytes_needed;
 164     }
 165   }
 166 
 167   // Finally take from the already committed region in the other space.
 168   tmp_bytes = bytes_needed;
 169   if (tmp_bytes > 0) {
 170     // Reduce both committed and reserved in the other space.
 171     other_space->set_committed(other_space->committed_low_addr() + tmp_bytes,
 172                                other_space->committed_high_addr());
 173     other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 174                               other_space->reserved_high_addr(),
 175                               other_space->special());
 176 
 177     // Grow both reserved and committed in this space.
 178     _reserved_high_addr += tmp_bytes;
 179     _committed_high_addr += tmp_bytes;
 180   }
 181 
 182   return bytes;
 183 }
 184 
 185 #ifndef PRODUCT
 186 bool PSVirtualSpace::is_aligned(size_t value, size_t align) {
 187   const size_t tmp_value = value + align - 1;
 188   const size_t mask = ~(align - 1);
 189   return (tmp_value & mask) == value;
 190 }
 191 
 192 bool PSVirtualSpace::is_aligned(size_t value) const {
 193   return is_aligned(value, alignment());
 194 }
 195 
 196 bool PSVirtualSpace::is_aligned(char* value) const {
 197   return is_aligned((size_t)value);
 198 }
 199 
 200 void PSVirtualSpace::verify() const {
 201   assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment");
 202   assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr");
 203   assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr");
 204   assert(is_aligned(committed_low_addr()), "bad committed_low_addr");
 205   assert(is_aligned(committed_high_addr()), "bad committed_high_addr");
 206 
 207   // Reserved region must be non-empty or both addrs must be 0.
 208   assert(reserved_low_addr() < reserved_high_addr() ||
 209          reserved_low_addr() == NULL && reserved_high_addr() == NULL,
 210          "bad reserved addrs");
 211   assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs");
 212 
 213   if (grows_up()) {
 214     assert(reserved_low_addr() == committed_low_addr(), "bad low addrs");
 215     assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs");
 216   } else {
 217     assert(reserved_high_addr() == committed_high_addr(), "bad high addrs");
 218     assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs");
 219   }
 220 }
 221 
 222 #endif // #ifndef PRODUCT
 223 
 224 void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const {
 225   st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")",
 226                p2i(low_boundary()), p2i(high()), p2i(high_boundary()));
 227 }