1 /*
   2  * Copyright (c) 2003, 2013, 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_implementation/parallelScavenge/psVirtualspace.hpp"
  27 #include "runtime/os.hpp"
  28 #include "runtime/virtualspace.hpp"
  29 #ifdef TARGET_OS_FAMILY_linux
  30 # include "os_linux.inline.hpp"
  31 #endif
  32 #ifdef TARGET_OS_FAMILY_solaris
  33 # include "os_solaris.inline.hpp"
  34 #endif
  35 #ifdef TARGET_OS_FAMILY_windows
  36 # include "os_windows.inline.hpp"
  37 #endif
  38 #ifdef TARGET_OS_FAMILY_aix
  39 # include "os_aix.inline.hpp"
  40 #endif
  41 #ifdef TARGET_OS_FAMILY_bsd
  42 # include "os_bsd.inline.hpp"
  43 #endif
  44 
  45 // PSVirtualSpace
  46 
  47 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) :
  48   _alignment(alignment)
  49 {
  50   set_reserved(rs);
  51   set_committed(reserved_low_addr(), reserved_low_addr());
  52   DEBUG_ONLY(verify());
  53 }
  54 
  55 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) :
  56   _alignment(os::vm_page_size())
  57 {
  58   set_reserved(rs);
  59   set_committed(reserved_low_addr(), reserved_low_addr());
  60   DEBUG_ONLY(verify());
  61 }
  62 
  63 // Deprecated.
  64 PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()) {
  65 }
  66 
  67 // Deprecated.
  68 bool PSVirtualSpace::initialize(ReservedSpace rs,
  69                                 size_t commit_size) {
  70   set_reserved(rs);
  71   set_committed(reserved_low_addr(), reserved_low_addr());
  72 
  73   // Commit to initial size.
  74   assert(commit_size <= rs.size(), "commit_size too big");
  75   bool result = commit_size > 0 ? expand_by(commit_size) : true;
  76   DEBUG_ONLY(verify());
  77   return result;
  78 }
  79 
  80 PSVirtualSpace::~PSVirtualSpace() {
  81   release();
  82 }
  83 
  84 bool PSVirtualSpace::contains(void* p) const {
  85   char* const cp = (char*)p;
  86   return cp >= committed_low_addr() && cp < committed_high_addr();
  87 }
  88 
  89 void PSVirtualSpace::release() {
  90   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
  91   // This may not release memory it didn't reserve.
  92   // Use rs.release() to release the underlying memory instead.
  93   _reserved_low_addr = _reserved_high_addr = NULL;
  94   _committed_low_addr = _committed_high_addr = NULL;
  95   _special = false;
  96 }
  97 
  98 bool PSVirtualSpace::expand_by(size_t bytes) {
  99   assert(is_aligned(bytes), "arg not aligned");
 100   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 101 
 102   if (uncommitted_size() < bytes) {
 103     return false;
 104   }
 105 
 106   char* const base_addr = committed_high_addr();
 107   bool result = special() ||
 108          os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
 109   if (result) {
 110     _committed_high_addr += bytes;
 111   }
 112 
 113   return result;
 114 }
 115 
 116 bool PSVirtualSpace::shrink_by(size_t bytes) {
 117   assert(is_aligned(bytes), "arg not aligned");
 118   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 119 
 120   if (committed_size() < bytes) {
 121     return false;
 122   }
 123 
 124   char* const base_addr = committed_high_addr() - bytes;
 125   bool result = special() || os::uncommit_memory(base_addr, bytes);
 126   if (result) {
 127     _committed_high_addr -= bytes;
 128   }
 129 
 130   return result;
 131 }
 132 
 133 size_t
 134 PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) {
 135   assert(is_aligned(bytes), "arg not aligned");
 136   assert(grows_up(), "this space must grow up");
 137   assert(other_space->grows_down(), "other space must grow down");
 138   assert(reserved_high_addr() == other_space->reserved_low_addr(),
 139          "spaces not contiguous");
 140   assert(special() == other_space->special(), "one space is special, the other is not");
 141   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 142   DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
 143 
 144   size_t bytes_needed = bytes;
 145 
 146   // First use the uncommitted region in this space.
 147   size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
 148   if (tmp_bytes > 0) {
 149     if (expand_by(tmp_bytes)) {
 150       bytes_needed -= tmp_bytes;
 151     } else {
 152       return 0;
 153     }
 154   }
 155 
 156   // Next take from the uncommitted region in the other space, and commit it.
 157   tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
 158   if (tmp_bytes > 0) {
 159     char* const commit_base = committed_high_addr();
 160     if (other_space->special() ||
 161         os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) {
 162       // Reduce the reserved region in the other space.
 163       other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 164                                 other_space->reserved_high_addr(),
 165                                 other_space->special());
 166 
 167       // Grow both reserved and committed in this space.
 168       _reserved_high_addr += tmp_bytes;
 169       _committed_high_addr += tmp_bytes;
 170       bytes_needed -= tmp_bytes;
 171     } else {
 172       return bytes - bytes_needed;
 173     }
 174   }
 175 
 176   // Finally take from the already committed region in the other space.
 177   tmp_bytes = bytes_needed;
 178   if (tmp_bytes > 0) {
 179     // Reduce both committed and reserved in the other space.
 180     other_space->set_committed(other_space->committed_low_addr() + tmp_bytes,
 181                                other_space->committed_high_addr());
 182     other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 183                               other_space->reserved_high_addr(),
 184                               other_space->special());
 185 
 186     // Grow both reserved and committed in this space.
 187     _reserved_high_addr += tmp_bytes;
 188     _committed_high_addr += tmp_bytes;
 189   }
 190 
 191   return bytes;
 192 }
 193 
 194 #ifndef PRODUCT
 195 bool PSVirtualSpace::is_aligned(size_t value, size_t align) {
 196   const size_t tmp_value = value + align - 1;
 197   const size_t mask = ~(align - 1);
 198   return (tmp_value & mask) == value;
 199 }
 200 
 201 bool PSVirtualSpace::is_aligned(size_t value) const {
 202   return is_aligned(value, alignment());
 203 }
 204 
 205 bool PSVirtualSpace::is_aligned(char* value) const {
 206   return is_aligned((size_t)value);
 207 }
 208 
 209 void PSVirtualSpace::verify() const {
 210   assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment");
 211   assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr");
 212   assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr");
 213   assert(is_aligned(committed_low_addr()), "bad committed_low_addr");
 214   assert(is_aligned(committed_high_addr()), "bad committed_high_addr");
 215 
 216   // Reserved region must be non-empty or both addrs must be 0.
 217   assert(reserved_low_addr() < reserved_high_addr() ||
 218          reserved_low_addr() == NULL && reserved_high_addr() == NULL,
 219          "bad reserved addrs");
 220   assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs");
 221 
 222   if (grows_up()) {
 223     assert(reserved_low_addr() == committed_low_addr(), "bad low addrs");
 224     assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs");
 225   } else {
 226     assert(reserved_high_addr() == committed_high_addr(), "bad high addrs");
 227     assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs");
 228   }
 229 }
 230 
 231 void PSVirtualSpace::print() const {
 232   gclog_or_tty->print_cr("virtual space [" PTR_FORMAT "]:  alignment="
 233                          SIZE_FORMAT "K grows %s%s",
 234                          this, alignment() / K, grows_up() ? "up" : "down",
 235                          special() ? " (pinned in memory)" : "");
 236   gclog_or_tty->print_cr("    reserved=" SIZE_FORMAT "K"
 237                          " [" PTR_FORMAT "," PTR_FORMAT "]"
 238                          " committed=" SIZE_FORMAT "K"
 239                          " [" PTR_FORMAT "," PTR_FORMAT "]",
 240                          reserved_size() / K,
 241                          reserved_low_addr(), reserved_high_addr(),
 242                          committed_size() / K,
 243                          committed_low_addr(), committed_high_addr());
 244 }
 245 #endif // #ifndef PRODUCT
 246 
 247 void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const {
 248   st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")",
 249                low_boundary(), high(), high_boundary());
 250 }
 251 
 252 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs,
 253                                                  size_t alignment) :
 254   PSVirtualSpace(alignment)
 255 {
 256   set_reserved(rs);
 257   set_committed(reserved_high_addr(), reserved_high_addr());
 258   DEBUG_ONLY(verify());
 259 }
 260 
 261 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs) {
 262   set_reserved(rs);
 263   set_committed(reserved_high_addr(), reserved_high_addr());
 264   DEBUG_ONLY(verify());
 265 }
 266 
 267 bool PSVirtualSpaceHighToLow::expand_by(size_t bytes) {
 268   assert(is_aligned(bytes), "arg not aligned");
 269   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 270 
 271   if (uncommitted_size() < bytes) {
 272     return false;
 273   }
 274 
 275   char* const base_addr = committed_low_addr() - bytes;
 276   bool result = special() ||
 277          os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
 278   if (result) {
 279     _committed_low_addr -= bytes;
 280   }
 281 
 282   return result;
 283 }
 284 
 285 bool PSVirtualSpaceHighToLow::shrink_by(size_t bytes) {
 286   assert(is_aligned(bytes), "arg not aligned");
 287   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 288 
 289   if (committed_size() < bytes) {
 290     return false;
 291   }
 292 
 293   char* const base_addr = committed_low_addr();
 294   bool result = special() || os::uncommit_memory(base_addr, bytes);
 295   if (result) {
 296     _committed_low_addr += bytes;
 297   }
 298 
 299   return result;
 300 }
 301 
 302 size_t PSVirtualSpaceHighToLow::expand_into(PSVirtualSpace* other_space,
 303                                             size_t bytes) {
 304   assert(is_aligned(bytes), "arg not aligned");
 305   assert(grows_down(), "this space must grow down");
 306   assert(other_space->grows_up(), "other space must grow up");
 307   assert(reserved_low_addr() == other_space->reserved_high_addr(),
 308          "spaces not contiguous");
 309   assert(special() == other_space->special(), "one space is special in memory, the other is not");
 310   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 311   DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
 312 
 313   size_t bytes_needed = bytes;
 314 
 315   // First use the uncommitted region in this space.
 316   size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
 317   if (tmp_bytes > 0) {
 318     if (expand_by(tmp_bytes)) {
 319       bytes_needed -= tmp_bytes;
 320     } else {
 321       return 0;
 322     }
 323   }
 324 
 325   // Next take from the uncommitted region in the other space, and commit it.
 326   tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
 327   if (tmp_bytes > 0) {
 328     char* const commit_base = committed_low_addr() - tmp_bytes;
 329     if (other_space->special() ||
 330         os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) {
 331       // Reduce the reserved region in the other space.
 332       other_space->set_reserved(other_space->reserved_low_addr(),
 333                                 other_space->reserved_high_addr() - tmp_bytes,
 334                                 other_space->special());
 335 
 336       // Grow both reserved and committed in this space.
 337       _reserved_low_addr -= tmp_bytes;
 338       _committed_low_addr -= tmp_bytes;
 339       bytes_needed -= tmp_bytes;
 340     } else {
 341       return bytes - bytes_needed;
 342     }
 343   }
 344 
 345   // Finally take from the already committed region in the other space.
 346   tmp_bytes = bytes_needed;
 347   if (tmp_bytes > 0) {
 348     // Reduce both committed and reserved in the other space.
 349     other_space->set_committed(other_space->committed_low_addr(),
 350                                other_space->committed_high_addr() - tmp_bytes);
 351     other_space->set_reserved(other_space->reserved_low_addr(),
 352                               other_space->reserved_high_addr() - tmp_bytes,
 353                               other_space->special());
 354 
 355     // Grow both reserved and committed in this space.
 356     _reserved_low_addr -= tmp_bytes;
 357     _committed_low_addr -= tmp_bytes;
 358   }
 359 
 360   return bytes;
 361 }
 362 
 363 void
 364 PSVirtualSpaceHighToLow::print_space_boundaries_on(outputStream* st) const {
 365   st->print_cr(" (" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]",
 366                high_boundary(), low(), low_boundary());
 367 }