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