src/Spaces.cpp
author David Anderson <danderson@mozilla.com>
Wed Jul 25 00:48:08 2012 -0700 (2012-07-25)
changeset 91 5f4402180204
parent 86 32ad0523b309
child 92 e3974e7360e9
permissions -rw-r--r--
Added clang support. A lot of the motion here is introducing a new offsetof because clang's seems broken?
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <string.h>
    20 #include "Zone.h"
    21 #include "Spaces.h"
    22 #include "Platform.h"
    23 #include "Spaces-inl.h"
    24 
    25 using namespace ke;
    26 
    27 HeapStack::HeapStack()
    28   : chunk_(NULL),
    29     cursor_(NULL)
    30 {
    31 }
    32 
    33 HeapStack::~HeapStack()
    34 {
    35     if (chunk_)
    36         HeapChunk::Destroy(chunk_);
    37 }
    38 
    39 bool
    40 HeapStack::initialize()
    41 {
    42     chunk_ = HeapChunk::New(NULL, kStackSize);
    43     cursor_ = chunk_->first();
    44     return true;
    45 }
    46 
    47 HeapChunk *
    48 HeapChunk::New(HeapChunk *prev, size_t size)
    49 {
    50     OS::AlignableMapping map = 
    51         OS::MapAlignedMemory(size, HeapChunk::kAlignment, OS::Map_Commit);
    52 
    53     if (!map.base())
    54         return NULL;
    55 
    56     HeapChunk *chunk = reinterpret_cast<HeapChunk *>(map.aligned());
    57     chunk->base_ = map.base();
    58     chunk->end_ = map.base() + map.size();
    59     if (prev)
    60         prev->next_ = chunk;
    61 
    62     return chunk;
    63 }
    64 
    65 void
    66 HeapChunk::Destroy(HeapChunk *chunk)
    67 {
    68     OS::UnmapAlignedMemory(chunk->base(), chunk->size());
    69 }
    70 
    71 void
    72 HeapChunk::resetMarkBits()
    73 {
    74     memset(markBits(), 0, kMarkBytes);
    75 }
    76 
    77 FreeList::FreeList()
    78   : small_objects_(NULL),
    79     medium_objects_(NULL),
    80     large_objects_(NULL),
    81     huge_objects_(NULL)
    82 {
    83 }
    84 
    85 void
    86 FreeList::add(FreedObject *obj)
    87 {
    88     if (obj->size() < kMinObjectSize) 
    89         return;
    90 
    91     FreedObject **list;
    92     if (obj->size() < kMaxSmallObject)
    93         list = &small_objects_;
    94     else if (obj->size() < kMaxMediumObject)
    95         list = &medium_objects_;
    96     else if (obj->size() < kMaxLargeObject)
    97         list = &large_objects_;
    98     else
    99         list = &huge_objects_;
   100 
   101     if (*list)
   102         (*list)->setNext(obj);
   103     *list = obj;
   104 }
   105 
   106 FreedObject *
   107 FreeList::pick(size_t size)
   108 {
   109     if (size < kMinObjectSize && small_objects_) {
   110         FreedObject *obj = small_objects_;
   111         small_objects_ = small_objects_->next();
   112         return obj;
   113     }
   114     if (size < kMaxSmallObject && medium_objects_) {
   115         FreedObject *obj = medium_objects_;
   116         medium_objects_ = medium_objects_->next();
   117         return obj;
   118     }
   119     if (size < kMaxMediumObject && large_objects_) {
   120         FreedObject *obj = large_objects_;
   121         large_objects_ = large_objects_->next();
   122         return obj;
   123     }
   124     if (huge_objects_) {
   125         FreedObject *obj = huge_objects_;
   126         huge_objects_ = huge_objects_->next();
   127         return obj;
   128     }
   129     return NULL;
   130 }
   131 
   132 void
   133 FreeList::reset()
   134 {
   135     small_objects_ = NULL;
   136     medium_objects_ = NULL;
   137     large_objects_ = NULL;
   138     huge_objects_ = NULL;
   139 }
   140 
   141 OldSpace::OldSpace(Zone *zone)
   142   : zone_(zone),
   143     first_(NULL),
   144     last_(NULL)
   145 {
   146 }
   147 
   148 bool
   149 OldSpace::initialize()
   150 {
   151     first_ = HeapChunk::New(first_, HeapChunk::kDefaultSize);
   152     last_ = first_;
   153     cursor_ = first_->first();
   154 
   155     return !!first_;
   156 }
   157 
   158 OldSpace::~OldSpace()
   159 {
   160     while (first_) {
   161         HeapChunk *temp = first_->next();
   162         HeapChunk::Destroy(first_);
   163         first_ = temp;
   164     }
   165 }
   166 
   167 Address
   168 OldSpace::allocateSlow(size_t nbytes)
   169 {
   170     if (FreedObject *obj = freelist_.pick(nbytes)) {
   171         Address address = reinterpret_cast<Address>(obj);
   172         size_t actual = obj->size();
   173         assert(actual >= nbytes);
   174         if (actual != nbytes)
   175             markRegionFree(address + nbytes, actual - nbytes);
   176 
   177         return address;
   178     }
   179 
   180     // Free unused stuff at the end of the current chunk.
   181     if (cursor_ != last_->end())
   182         markRegionFree(cursor_, last_->end() - cursor_);
   183 
   184     HeapChunk *chunk;
   185     if (last_->next()) {
   186         // The next chunk is guaranteed to be empty.
   187         chunk = last_->next();
   188     } else {
   189         chunk = HeapChunk::New(last_, HeapChunk::kDefaultSize);
   190         if (!chunk)
   191             return NULL;
   192     }
   193 
   194     last_ = chunk;
   195     cursor_ = chunk->first();
   196 
   197     assert(cursor_ + nbytes <= chunk->end());
   198 
   199     Address address = cursor_;
   200     cursor_ += nbytes;
   201     return address;
   202 }
   203 
   204 void
   205 OldSpace::markRegionFree(Address start, size_t length)
   206 {
   207     FreedObject *obj = reinterpret_cast<FreedObject *>(start);
   208     new (obj) FreedObject(zone_->getMap(MapKind_FreeRegion), length);
   209 
   210     if (length < sizeof(FreedObject)) {
   211         // Can't encode a list in this object, but it's marked free, so we're done.
   212         return;
   213     }
   214 
   215     freelist_.add(obj);
   216 }
   217 
   218 void
   219 OldSpace::freeUnusedPages()
   220 {
   221     HeapChunk **prev = &first_;
   222     HeapChunk *empty = NULL;
   223     while (*prev) {
   224         HeapChunk *chunk = *prev;
   225         if (chunk->isEmpty()) {
   226             *prev = chunk->next();
   227             if (empty) {
   228                 // Remove this chunk.
   229                 HeapChunk::Destroy(chunk);
   230                 continue;
   231             }
   232             empty = chunk;                
   233         }
   234         prev = chunk->nextp();
   235     }
   236 
   237     if (empty) {
   238         *empty->nextp() = NULL;
   239         *last_->nextp() = empty;
   240     }
   241 }
   242 
   243 void
   244 OldSpace::resetFreeList()
   245 {
   246     freelist_.reset();
   247 }
   248 
   249 LargeObjectSpace::LargeObjectSpace()
   250   : first_(NULL),
   251     last_(NULL)
   252 {
   253 }
   254 
   255 LargeObjectSpace::~LargeObjectSpace()
   256 {
   257     while (first_) {
   258         HeapChunk *temp = first_->next();
   259         HeapChunk::Destroy(first_);
   260         first_ = temp;
   261     }
   262 }
   263 
   264 bool
   265 LargeObjectSpace::initialize()
   266 {
   267     return true;
   268 }
   269 
   270 Address
   271 LargeObjectSpace::allocate(size_t nbytes)
   272 {
   273     assert(IsAligned(nbytes, kObjectAlignment));
   274 
   275     // Always allocate a new chunk for large objects.
   276     HeapChunk *chunk = HeapChunk::New(last_, nbytes);
   277     if (!chunk)
   278         return NULL;
   279 
   280     if (!first_)
   281         first_ = chunk;
   282     last_ = chunk;
   283 
   284     return chunk->first();
   285 }
   286 
   287 void
   288 LargeObjectSpace::sweep()
   289 {
   290     if (!first_)
   291         return;
   292 
   293     HeapChunk **pprev = &first_;
   294     do {
   295         HeapChunk *chunk = *pprev;
   296         Object *obj = reinterpret_cast<Object *>(chunk->first());
   297         MarkBit bit = HeapChunk::GetMarkBit(obj);
   298         if (HeapChunk::IsWhite(bit)) {
   299             *pprev = chunk->next();
   300             HeapChunk::Destroy(chunk);
   301         } else {
   302             assert(HeapChunk::IsBlack(bit));
   303             HeapChunk::Clear(bit);
   304             pprev = chunk->nextp();
   305             last_ = chunk;
   306         }
   307     } while (*pprev);
   308 }