Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "zone-inl.h"
     31 #include "splay-tree-inl.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 Zone::Zone()
     38     : zone_excess_limit_(256 * MB),
     39       segment_bytes_allocated_(0),
     40       position_(0),
     41       limit_(0),
     42       scope_nesting_(0),
     43       segment_head_(NULL) {
     44 }
     45 unsigned Zone::allocation_size_ = 0;
     46 
     47 
     48 ZoneScope::~ZoneScope() {
     49   ASSERT_EQ(Isolate::Current(), isolate_);
     50   if (ShouldDeleteOnExit()) isolate_->zone()->DeleteAll();
     51   isolate_->zone()->scope_nesting_--;
     52 }
     53 
     54 
     55 // Segments represent chunks of memory: They have starting address
     56 // (encoded in the this pointer) and a size in bytes. Segments are
     57 // chained together forming a LIFO structure with the newest segment
     58 // available as segment_head_. Segments are allocated using malloc()
     59 // and de-allocated using free().
     60 
     61 class Segment {
     62  public:
     63   Segment* next() const { return next_; }
     64   void clear_next() { next_ = NULL; }
     65 
     66   int size() const { return size_; }
     67   int capacity() const { return size_ - sizeof(Segment); }
     68 
     69   Address start() const { return address(sizeof(Segment)); }
     70   Address end() const { return address(size_); }
     71 
     72  private:
     73   // Computes the address of the nth byte in this segment.
     74   Address address(int n) const {
     75     return Address(this) + n;
     76   }
     77 
     78   Segment* next_;
     79   int size_;
     80 
     81   friend class Zone;
     82 };
     83 
     84 
     85 // Creates a new segment, sets it size, and pushes it to the front
     86 // of the segment chain. Returns the new segment.
     87 Segment* Zone::NewSegment(int size) {
     88   Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
     89   adjust_segment_bytes_allocated(size);
     90   if (result != NULL) {
     91     result->next_ = segment_head_;
     92     result->size_ = size;
     93     segment_head_ = result;
     94   }
     95   return result;
     96 }
     97 
     98 
     99 // Deletes the given segment. Does not touch the segment chain.
    100 void Zone::DeleteSegment(Segment* segment, int size) {
    101   adjust_segment_bytes_allocated(-size);
    102   Malloced::Delete(segment);
    103 }
    104 
    105 
    106 void Zone::DeleteAll() {
    107 #ifdef DEBUG
    108   // Constant byte value used for zapping dead memory in debug mode.
    109   static const unsigned char kZapDeadByte = 0xcd;
    110 #endif
    111 
    112   // Find a segment with a suitable size to keep around.
    113   Segment* keep = segment_head_;
    114   while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
    115     keep = keep->next();
    116   }
    117 
    118   // Traverse the chained list of segments, zapping (in debug mode)
    119   // and freeing every segment except the one we wish to keep.
    120   Segment* current = segment_head_;
    121   while (current != NULL) {
    122     Segment* next = current->next();
    123     if (current == keep) {
    124       // Unlink the segment we wish to keep from the list.
    125       current->clear_next();
    126     } else {
    127       int size = current->size();
    128 #ifdef DEBUG
    129       // Zap the entire current segment (including the header).
    130       memset(current, kZapDeadByte, size);
    131 #endif
    132       DeleteSegment(current, size);
    133     }
    134     current = next;
    135   }
    136 
    137   // If we have found a segment we want to keep, we must recompute the
    138   // variables 'position' and 'limit' to prepare for future allocate
    139   // attempts. Otherwise, we must clear the position and limit to
    140   // force a new segment to be allocated on demand.
    141   if (keep != NULL) {
    142     Address start = keep->start();
    143     position_ = RoundUp(start, kAlignment);
    144     limit_ = keep->end();
    145 #ifdef DEBUG
    146     // Zap the contents of the kept segment (but not the header).
    147     memset(start, kZapDeadByte, keep->capacity());
    148 #endif
    149   } else {
    150     position_ = limit_ = 0;
    151   }
    152 
    153   // Update the head segment to be the kept segment (if any).
    154   segment_head_ = keep;
    155 }
    156 
    157 
    158 Address Zone::NewExpand(int size) {
    159   // Make sure the requested size is already properly aligned and that
    160   // there isn't enough room in the Zone to satisfy the request.
    161   ASSERT(size == RoundDown(size, kAlignment));
    162   ASSERT(position_ + size > limit_);
    163 
    164   // Compute the new segment size. We use a 'high water mark'
    165   // strategy, where we increase the segment size every time we expand
    166   // except that we employ a maximum segment size when we delete. This
    167   // is to avoid excessive malloc() and free() overhead.
    168   Segment* head = segment_head_;
    169   int old_size = (head == NULL) ? 0 : head->size();
    170   static const int kSegmentOverhead = sizeof(Segment) + kAlignment;
    171   int new_size = kSegmentOverhead + size + (old_size << 1);
    172   if (new_size < kMinimumSegmentSize) {
    173     new_size = kMinimumSegmentSize;
    174   } else if (new_size > kMaximumSegmentSize) {
    175     // Limit the size of new segments to avoid growing the segment size
    176     // exponentially, thus putting pressure on contiguous virtual address space.
    177     // All the while making sure to allocate a segment large enough to hold the
    178     // requested size.
    179     new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize);
    180   }
    181   Segment* segment = NewSegment(new_size);
    182   if (segment == NULL) {
    183     V8::FatalProcessOutOfMemory("Zone");
    184     return NULL;
    185   }
    186 
    187   // Recompute 'top' and 'limit' based on the new segment.
    188   Address result = RoundUp(segment->start(), kAlignment);
    189   position_ = result + size;
    190   limit_ = segment->end();
    191   ASSERT(position_ <= limit_);
    192   return result;
    193 }
    194 
    195 
    196 } }  // namespace v8::internal
    197