00001 // Copyright 2006-2008 the V8 project authors. All rights reserved. 00002 // Redistribution and use in source and binary forms, with or without 00003 // modification, are permitted provided that the following conditions are 00004 // met: 00005 // 00006 // * Redistributions of source code must retain the above copyright 00007 // notice, this list of conditions and the following disclaimer. 00008 // * Redistributions in binary form must reproduce the above 00009 // copyright notice, this list of conditions and the following 00010 // disclaimer in the documentation and/or other materials provided 00011 // with the distribution. 00012 // * Neither the name of Google Inc. nor the names of its 00013 // contributors may be used to endorse or promote products derived 00014 // from this software without specific prior written permission. 00015 // 00016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00017 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00018 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00019 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00020 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00021 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00026 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 00028 #include "v8.h" 00029 00030 #include "zone-inl.h" 00031 00032 namespace v8 { namespace internal { 00033 00034 00035 Address Zone::position_ = 0; 00036 Address Zone::limit_ = 0; 00037 00038 bool AssertNoZoneAllocation::allow_allocation_ = true; 00039 00040 int ZoneScope::nesting_ = 0; 00041 00042 // Segments represent chunks of memory: They have starting address 00043 // (encoded in the this pointer) and a size in bytes. Segments are 00044 // chained together forming a LIFO structure with the newest segment 00045 // available as Segment::head(). Segments are allocated using malloc() 00046 // and de-allocated using free(). 00047 00048 class Segment { 00049 public: 00050 Segment* next() const { return next_; } 00051 void clear_next() { next_ = NULL; } 00052 00053 int size() const { return size_; } 00054 int capacity() const { return size_ - sizeof(Segment); } 00055 00056 Address start() const { return address(sizeof(Segment)); } 00057 Address end() const { return address(size_); } 00058 00059 static Segment* head() { return head_; } 00060 static void set_head(Segment* head) { head_ = head; } 00061 00062 // Creates a new segment, sets it size, and pushes it to the front 00063 // of the segment chain. Returns the new segment. 00064 static Segment* New(int size) { 00065 Segment* result = reinterpret_cast<Segment*>(Malloced::New(size)); 00066 if (result != NULL) { 00067 result->next_ = head_; 00068 result->size_ = size; 00069 head_ = result; 00070 } 00071 return result; 00072 } 00073 00074 // Deletes the given segment. Does not touch the segment chain. 00075 static void Delete(Segment* segment) { 00076 Malloced::Delete(segment); 00077 } 00078 00079 private: 00080 // Computes the address of the nth byte in this segment. 00081 Address address(int n) const { 00082 return Address(this) + n; 00083 } 00084 00085 static Segment* head_; 00086 Segment* next_; 00087 int size_; 00088 }; 00089 00090 00091 Segment* Segment::head_ = NULL; 00092 00093 00094 void Zone::DeleteAll() { 00095 #ifdef DEBUG 00096 // Constant byte value used for zapping dead memory in debug mode. 00097 static const unsigned char kZapDeadByte = 0xcd; 00098 #endif 00099 00100 // Find a segment with a suitable size to keep around. 00101 Segment* keep = Segment::head(); 00102 while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) { 00103 keep = keep->next(); 00104 } 00105 00106 // Traverse the chained list of segments, zapping (in debug mode) 00107 // and freeing every segment except the one we wish to keep. 00108 Segment* current = Segment::head(); 00109 while (current != NULL) { 00110 Segment* next = current->next(); 00111 if (current == keep) { 00112 // Unlink the segment we wish to keep from the list. 00113 current->clear_next(); 00114 } else { 00115 #ifdef DEBUG 00116 // Zap the entire current segment (including the header). 00117 memset(current, kZapDeadByte, current->size()); 00118 #endif 00119 Segment::Delete(current); 00120 } 00121 current = next; 00122 } 00123 00124 // If we have found a segment we want to keep, we must recompute the 00125 // variables 'position' and 'limit' to prepare for future allocate 00126 // attempts. Otherwise, we must clear the position and limit to 00127 // force a new segment to be allocated on demand. 00128 if (keep != NULL) { 00129 Address start = keep->start(); 00130 position_ = RoundUp(start, kAlignment); 00131 limit_ = keep->end(); 00132 #ifdef DEBUG 00133 // Zap the contents of the kept segment (but not the header). 00134 memset(start, kZapDeadByte, keep->capacity()); 00135 #endif 00136 } else { 00137 position_ = limit_ = 0; 00138 } 00139 00140 // Update the head segment to be the kept segment (if any). 00141 Segment::set_head(keep); 00142 } 00143 00144 00145 Address Zone::NewExpand(int size) { 00146 // Make sure the requested size is already properly aligned and that 00147 // there isn't enough room in the Zone to satisfy the request. 00148 ASSERT(size == RoundDown(size, kAlignment)); 00149 ASSERT(position_ + size > limit_); 00150 00151 // Compute the new segment size. We use a 'high water mark' 00152 // strategy, where we increase the segment size every time we expand 00153 // except that we employ a maximum segment size when we delete. This 00154 // is to avoid excessive malloc() and free() overhead. 00155 Segment* head = Segment::head(); 00156 int old_size = (head == NULL) ? 0 : head->size(); 00157 int new_size = sizeof(Segment) + kAlignment + size + (old_size << 1); 00158 if (new_size < kMinimumSegmentSize) new_size = kMinimumSegmentSize; 00159 Segment* segment = Segment::New(new_size); 00160 if (segment == NULL) V8::FatalProcessOutOfMemory("Zone"); 00161 00162 // Recompute 'top' and 'limit' based on the new segment. 00163 Address result = RoundUp(segment->start(), kAlignment); 00164 position_ = result + size; 00165 limit_ = segment->end(); 00166 ASSERT(position_ <= limit_); 00167 return result; 00168 } 00169 00170 00171 } } // namespace v8::internal