1 #ifdef USE_PRAGMA_IDENT_SRC
   2 #pragma ident "@(#)psVirtualspace.cpp   1.16 07/05/05 17:05:31 JVM"
   3 #endif
   4 /*
   5  * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
   6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   7  *
   8  * This code is free software; you can redistribute it and/or modify it
   9  * under the terms of the GNU General Public License version 2 only, as
  10  * published by the Free Software Foundation.
  11  *
  12  * This code is distributed in the hope that it will be useful, but WITHOUT
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15  * version 2 for more details (a copy is included in the LICENSE file that
  16  * accompanied this code).
  17  *
  18  * You should have received a copy of the GNU General Public License version
  19  * 2 along with this work; if not, write to the Free Software Foundation,
  20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21  *
  22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  23  * CA 95054 USA or visit www.sun.com if you need additional information or
  24  * have any questions.
  25  *  
  26  */
  27 
  28 #include "incls/_precompiled.incl"
  29 #include "incls/_psVirtualspace.cpp.incl"
  30 
  31 // PSVirtualSpace
  32 
  33 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs, size_t alignment) :
  34   _alignment(alignment)
  35 {
  36   set_reserved(rs);
  37   set_committed(reserved_low_addr(), reserved_low_addr());
  38   DEBUG_ONLY(verify());
  39 }
  40 
  41 PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) :
  42   _alignment(os::vm_page_size())
  43 {
  44   set_reserved(rs);
  45   set_committed(reserved_low_addr(), reserved_low_addr());
  46   DEBUG_ONLY(verify());
  47 }
  48 
  49 // Deprecated.
  50 PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()) {
  51 }
  52 
  53 // Deprecated.
  54 bool PSVirtualSpace::initialize(ReservedSpace rs,
  55                                 size_t commit_size) {
  56   set_reserved(rs);
  57   set_committed(reserved_low_addr(), reserved_low_addr());
  58 
  59   // Commit to initial size.
  60   assert(commit_size <= rs.size(), "commit_size too big");
  61   bool result = commit_size > 0 ? expand_by(commit_size) : true;
  62   DEBUG_ONLY(verify());
  63   return result;
  64 }
  65 
  66 PSVirtualSpace::~PSVirtualSpace() { 
  67   release();
  68 }
  69 
  70 bool PSVirtualSpace::contains(void* p) const {
  71   char* const cp = (char*)p;
  72   return cp >= committed_low_addr() && cp < committed_high_addr();
  73 }
  74 
  75 void PSVirtualSpace::release() {
  76   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
  77   // This may not release memory it didn't reserve.
  78   // Use rs.release() to release the underlying memory instead.
  79   _reserved_low_addr = _reserved_high_addr = NULL;
  80   _committed_low_addr = _committed_high_addr = NULL;
  81   _special = false;
  82 }
  83 
  84 bool PSVirtualSpace::expand_by(size_t bytes, bool pre_touch) {
  85   assert(is_aligned(bytes), "arg not aligned");
  86   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
  87 
  88   if (uncommitted_size() < bytes) {
  89     return false;
  90   }
  91 
  92   char* const base_addr = committed_high_addr();
  93   bool result = special() || os::commit_memory(base_addr, bytes, alignment());
  94   if (result) {
  95     _committed_high_addr += bytes;
  96   }
  97 
  98   if (pre_touch || AlwaysPreTouch) {
  99     for (char* curr = base_addr;
 100          curr < _committed_high_addr;
 101          curr += os::vm_page_size()) {
 102       char tmp = *curr;
 103       *curr = 0;
 104     }
 105   }
 106   
 107   return result;
 108 }
 109 
 110 bool PSVirtualSpace::shrink_by(size_t bytes) {
 111   assert(is_aligned(bytes), "arg not aligned");
 112   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 113 
 114   if (committed_size() < bytes) {
 115     return false;
 116   }
 117 
 118   char* const base_addr = committed_high_addr() - bytes;
 119   bool result = special() || os::uncommit_memory(base_addr, bytes);
 120   if (result) {
 121     _committed_high_addr -= bytes;
 122   }
 123 
 124   return result;
 125 }
 126 
 127 size_t
 128 PSVirtualSpace::expand_into(PSVirtualSpace* other_space, size_t bytes) {
 129   assert(is_aligned(bytes), "arg not aligned");
 130   assert(grows_up(), "this space must grow up");
 131   assert(other_space->grows_down(), "other space must grow down");
 132   assert(reserved_high_addr() == other_space->reserved_low_addr(),
 133          "spaces not contiguous");
 134   assert(special() == other_space->special(), "one space is special, the other is not");
 135   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 136   DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
 137 
 138   size_t bytes_needed = bytes;
 139 
 140   // First use the uncommitted region in this space.
 141   size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
 142   if (tmp_bytes > 0) {
 143     if (expand_by(tmp_bytes)) {
 144       bytes_needed -= tmp_bytes;
 145     } else {
 146       return 0;
 147     }
 148   }
 149 
 150   // Next take from the uncommitted region in the other space, and commit it.
 151   tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
 152   if (tmp_bytes > 0) {
 153     char* const commit_base = committed_high_addr();
 154     if (other_space->special() ||
 155         os::commit_memory(commit_base, tmp_bytes, alignment())) {
 156       // Reduce the reserved region in the other space.
 157       other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 158                                 other_space->reserved_high_addr(),
 159                                 other_space->special());
 160 
 161       // Grow both reserved and committed in this space.
 162       _reserved_high_addr += tmp_bytes;
 163       _committed_high_addr += tmp_bytes;
 164       bytes_needed -= tmp_bytes;
 165     } else {
 166       return bytes - bytes_needed;
 167     }
 168   }
 169 
 170   // Finally take from the already committed region in the other space.
 171   tmp_bytes = bytes_needed;
 172   if (tmp_bytes > 0) {
 173     // Reduce both committed and reserved in the other space.
 174     other_space->set_committed(other_space->committed_low_addr() + tmp_bytes,
 175                                other_space->committed_high_addr());
 176     other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes,
 177                               other_space->reserved_high_addr(),
 178                               other_space->special());
 179 
 180     // Grow both reserved and committed in this space.
 181     _reserved_high_addr += tmp_bytes;
 182     _committed_high_addr += tmp_bytes;
 183   }
 184 
 185   return bytes;
 186 }
 187 
 188 #ifndef PRODUCT
 189 bool PSVirtualSpace::is_aligned(size_t value, size_t align) {
 190   const size_t tmp_value = value + align - 1;
 191   const size_t mask = ~(align - 1);
 192   return (tmp_value & mask) == value;
 193 }
 194 
 195 bool PSVirtualSpace::is_aligned(size_t value) const {
 196   return is_aligned(value, alignment());
 197 }
 198 
 199 bool PSVirtualSpace::is_aligned(char* value) const {
 200   return is_aligned((size_t)value);
 201 }
 202 
 203 void PSVirtualSpace::verify() const {
 204   assert(is_aligned(alignment(), os::vm_page_size()), "bad alignment");
 205   assert(is_aligned(reserved_low_addr()), "bad reserved_low_addr");
 206   assert(is_aligned(reserved_high_addr()), "bad reserved_high_addr");
 207   assert(is_aligned(committed_low_addr()), "bad committed_low_addr");
 208   assert(is_aligned(committed_high_addr()), "bad committed_high_addr");
 209 
 210   // Reserved region must be non-empty or both addrs must be 0.
 211   assert(reserved_low_addr() < reserved_high_addr() ||
 212          reserved_low_addr() == NULL && reserved_high_addr() == NULL,
 213          "bad reserved addrs");
 214   assert(committed_low_addr() <= committed_high_addr(), "bad committed addrs");
 215 
 216   if (grows_up()) {
 217     assert(reserved_low_addr() == committed_low_addr(), "bad low addrs");
 218     assert(reserved_high_addr() >= committed_high_addr(), "bad high addrs");
 219   } else {
 220     assert(reserved_high_addr() == committed_high_addr(), "bad high addrs");
 221     assert(reserved_low_addr() <= committed_low_addr(), "bad low addrs");
 222   }
 223 }
 224 
 225 void PSVirtualSpace::print() const {
 226   gclog_or_tty->print_cr("virtual space [" PTR_FORMAT "]:  alignment="
 227                          SIZE_FORMAT "K grows %s%s",
 228                          this, alignment() / K, grows_up() ? "up" : "down",
 229                          special() ? " (pinned in memory)" : "");
 230   gclog_or_tty->print_cr("    reserved=" SIZE_FORMAT "K"
 231                          " [" PTR_FORMAT "," PTR_FORMAT "]"
 232                          " committed=" SIZE_FORMAT "K"
 233                          " [" PTR_FORMAT "," PTR_FORMAT "]",
 234                          reserved_size() / K,
 235                          reserved_low_addr(), reserved_high_addr(),
 236                          committed_size() / K,
 237                          committed_low_addr(), committed_high_addr());
 238 }
 239 #endif // #ifndef PRODUCT
 240 
 241 void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const {
 242   st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")",
 243                low_boundary(), high(), high_boundary());
 244 }
 245 
 246 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs,
 247                                                  size_t alignment) :
 248   PSVirtualSpace(alignment)
 249 {
 250   set_reserved(rs);
 251   set_committed(reserved_high_addr(), reserved_high_addr());
 252   DEBUG_ONLY(verify());
 253 }
 254 
 255 PSVirtualSpaceHighToLow::PSVirtualSpaceHighToLow(ReservedSpace rs) {
 256   set_reserved(rs);
 257   set_committed(reserved_high_addr(), reserved_high_addr());
 258   DEBUG_ONLY(verify());
 259 }
 260 
 261 bool PSVirtualSpaceHighToLow::expand_by(size_t bytes, bool pre_touch) {
 262   assert(is_aligned(bytes), "arg not aligned");
 263   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 264 
 265   if (uncommitted_size() < bytes) {
 266     return false;
 267   }
 268 
 269   char* const base_addr = committed_low_addr() - bytes;
 270   bool result = special() || os::commit_memory(base_addr, bytes, alignment());
 271   if (result) {
 272     _committed_low_addr -= bytes;
 273   }
 274 
 275   if (pre_touch || AlwaysPreTouch) {
 276     for (char* curr = base_addr;
 277          curr < _committed_high_addr;
 278          curr += os::vm_page_size()) {
 279       char tmp = *curr;
 280       *curr = 0;
 281     }
 282   }
 283   
 284   return result;
 285 }
 286 
 287 bool PSVirtualSpaceHighToLow::shrink_by(size_t bytes) {
 288   assert(is_aligned(bytes), "arg not aligned");
 289   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 290 
 291   if (committed_size() < bytes) {
 292     return false;
 293   }
 294 
 295   char* const base_addr = committed_low_addr();
 296   bool result = special() || os::uncommit_memory(base_addr, bytes);
 297   if (result) {
 298     _committed_low_addr += bytes;
 299   }
 300 
 301   return result;
 302 }
 303 
 304 size_t PSVirtualSpaceHighToLow::expand_into(PSVirtualSpace* other_space,
 305                                             size_t bytes) {
 306   assert(is_aligned(bytes), "arg not aligned");
 307   assert(grows_down(), "this space must grow down");
 308   assert(other_space->grows_up(), "other space must grow up");
 309   assert(reserved_low_addr() == other_space->reserved_high_addr(),
 310          "spaces not contiguous");
 311   assert(special() == other_space->special(), "one space is special in memory, the other is not");
 312   DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
 313   DEBUG_ONLY(PSVirtualSpaceVerifier other_verifier(other_space));
 314 
 315   size_t bytes_needed = bytes;
 316 
 317   // First use the uncommitted region in this space.
 318   size_t tmp_bytes = MIN2(uncommitted_size(), bytes_needed);
 319   if (tmp_bytes > 0) {
 320     if (expand_by(tmp_bytes)) {
 321       bytes_needed -= tmp_bytes;
 322     } else {
 323       return 0;
 324     }
 325   }
 326 
 327   // Next take from the uncommitted region in the other space, and commit it.
 328   tmp_bytes = MIN2(other_space->uncommitted_size(), bytes_needed);
 329   if (tmp_bytes > 0) {
 330     char* const commit_base = committed_low_addr() - tmp_bytes;
 331     if (other_space->special() ||
 332         os::commit_memory(commit_base, tmp_bytes, alignment())) {
 333       // Reduce the reserved region in the other space.
 334       other_space->set_reserved(other_space->reserved_low_addr(),
 335                                 other_space->reserved_high_addr() - tmp_bytes,
 336                                 other_space->special());
 337 
 338       // Grow both reserved and committed in this space.
 339       _reserved_low_addr -= tmp_bytes;
 340       _committed_low_addr -= tmp_bytes;
 341       bytes_needed -= tmp_bytes;
 342     } else {
 343       return bytes - bytes_needed;
 344     }
 345   }
 346 
 347   // Finally take from the already committed region in the other space.
 348   tmp_bytes = bytes_needed;
 349   if (tmp_bytes > 0) {
 350     // Reduce both committed and reserved in the other space.
 351     other_space->set_committed(other_space->committed_low_addr(),
 352                                other_space->committed_high_addr() - tmp_bytes);
 353     other_space->set_reserved(other_space->reserved_low_addr(),
 354                               other_space->reserved_high_addr() - tmp_bytes,
 355                               other_space->special());
 356 
 357     // Grow both reserved and committed in this space.
 358     _reserved_low_addr -= tmp_bytes;
 359     _committed_low_addr -= tmp_bytes;
 360   }
 361 
 362   return bytes;
 363 }
 364 
 365 void
 366 PSVirtualSpaceHighToLow::print_space_boundaries_on(outputStream* st) const {
 367   st->print_cr(" (" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]",
 368                high_boundary(), low(), low_boundary());
 369 }