src/Spaces.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jan 01 20:07:09 2013 -0800 (2013-01-01)
changeset 254 cd167be62cbe
parent 92 e3974e7360e9
permissions -rw-r--r--
Fix Linux build.
     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 #include "Heap-inl.h"
    25 
    26 using namespace ke;
    27 
    28 HeapStack::HeapStack()
    29   : chunk_(NULL),
    30     cursor_(NULL)
    31 {
    32 }
    33 
    34 HeapStack::~HeapStack()
    35 {
    36     if (chunk_)
    37         HeapChunk::Destroy(chunk_);
    38 }
    39 
    40 bool
    41 HeapStack::initialize()
    42 {
    43     chunk_ = HeapChunk::New(NULL, kStackSize);
    44     cursor_ = chunk_->first();
    45     return true;
    46 }
    47 
    48 HeapChunk *
    49 HeapChunk::New(HeapChunk *prev, size_t size)
    50 {
    51     OS::AlignableMapping map = 
    52         OS::MapAlignedMemory(size, HeapChunk::kAlignment, OS::Map_Commit);
    53 
    54     if (!map.base())
    55         return NULL;
    56 
    57     HeapChunk *chunk = reinterpret_cast<HeapChunk *>(map.aligned());
    58     chunk->base_ = map.base();
    59     chunk->end_ = map.base() + map.size();
    60     if (prev)
    61         prev->next_ = chunk;
    62 
    63     return chunk;
    64 }
    65 
    66 void
    67 HeapChunk::Destroy(HeapChunk *chunk)
    68 {
    69     OS::UnmapAlignedMemory(chunk->base(), chunk->size());
    70 }
    71 
    72 void
    73 HeapChunk::resetMarkBits()
    74 {
    75     memset(markBits(), 0, kMarkBytes);
    76 }
    77 
    78 FreeList::FreeList()
    79   : small_objects_(NULL),
    80     medium_objects_(NULL),
    81     large_objects_(NULL),
    82     huge_objects_(NULL)
    83 {
    84 }
    85 
    86 void
    87 FreeList::add(FreedObject *obj)
    88 {
    89     if (obj->size() < kMinObjectSize) 
    90         return;
    91 
    92     FreedObject **list;
    93     if (obj->size() < kMaxSmallObject)
    94         list = &small_objects_;
    95     else if (obj->size() < kMaxMediumObject)
    96         list = &medium_objects_;
    97     else if (obj->size() < kMaxLargeObject)
    98         list = &large_objects_;
    99     else
   100         list = &huge_objects_;
   101 
   102     if (*list)
   103         (*list)->setNext(obj);
   104     *list = obj;
   105 }
   106 
   107 FreedObject *
   108 FreeList::pick(size_t size)
   109 {
   110     if (size < kMinObjectSize && small_objects_) {
   111         FreedObject *obj = small_objects_;
   112         small_objects_ = small_objects_->next();
   113         return obj;
   114     }
   115     if (size < kMaxSmallObject && medium_objects_) {
   116         FreedObject *obj = medium_objects_;
   117         medium_objects_ = medium_objects_->next();
   118         return obj;
   119     }
   120     if (size < kMaxMediumObject && large_objects_) {
   121         FreedObject *obj = large_objects_;
   122         large_objects_ = large_objects_->next();
   123         return obj;
   124     }
   125     if (huge_objects_) {
   126         FreedObject *obj = huge_objects_;
   127         huge_objects_ = huge_objects_->next();
   128         return obj;
   129     }
   130     return NULL;
   131 }
   132 
   133 void
   134 FreeList::reset()
   135 {
   136     small_objects_ = NULL;
   137     medium_objects_ = NULL;
   138     large_objects_ = NULL;
   139     huge_objects_ = NULL;
   140 }
   141 
   142 OldSpace::OldSpace(Zone *zone)
   143   : zone_(zone),
   144     first_(NULL),
   145     last_(NULL)
   146 {
   147 }
   148 
   149 bool
   150 OldSpace::initialize()
   151 {
   152     first_ = HeapChunk::New(first_, HeapChunk::kDefaultSize);
   153     last_ = first_;
   154     cursor_ = first_->first();
   155 
   156     return !!first_;
   157 }
   158 
   159 OldSpace::~OldSpace()
   160 {
   161     while (first_) {
   162         HeapChunk *temp = first_->next();
   163         HeapChunk::Destroy(first_);
   164         first_ = temp;
   165     }
   166 }
   167 
   168 Address
   169 OldSpace::allocateSlow(size_t nbytes)
   170 {
   171     if (FreedObject *obj = freelist_.pick(nbytes)) {
   172         Address address = reinterpret_cast<Address>(obj);
   173         size_t actual = obj->size();
   174         assert(actual >= nbytes);
   175         if (actual != nbytes)
   176             markRegionFree(address + nbytes, actual - nbytes);
   177 
   178         return address;
   179     }
   180 
   181     // Free unused stuff at the end of the current chunk.
   182     if (cursor_ != last_->end())
   183         markRegionFree(cursor_, last_->end() - cursor_);
   184 
   185     HeapChunk *chunk;
   186     if (last_->next()) {
   187         // The next chunk is guaranteed to be empty.
   188         chunk = last_->next();
   189     } else {
   190         chunk = HeapChunk::New(last_, HeapChunk::kDefaultSize);
   191         if (!chunk)
   192             return NULL;
   193     }
   194 
   195     last_ = chunk;
   196     cursor_ = chunk->first();
   197 
   198     assert(cursor_ + nbytes <= chunk->end());
   199 
   200     Address address = cursor_;
   201     cursor_ += nbytes;
   202     return address;
   203 }
   204 
   205 void
   206 OldSpace::markRegionFree(Address start, size_t length)
   207 {
   208     FreedObject *obj = reinterpret_cast<FreedObject *>(start);
   209     new (obj) FreedObject(zone_->getMap(MapKind_FreeRegion), length);
   210 
   211     if (length < sizeof(FreedObject)) {
   212         // Can't encode a list in this object, but it's marked free, so we're done.
   213         return;
   214     }
   215 
   216     freelist_.add(obj);
   217 }
   218 
   219 void
   220 OldSpace::freeUnusedPages()
   221 {
   222     HeapChunk **prev = &first_;
   223     HeapChunk *empty = NULL;
   224     while (*prev) {
   225         HeapChunk *chunk = *prev;
   226         if (chunk->isEmpty()) {
   227             *prev = chunk->next();
   228             if (empty) {
   229                 // Remove this chunk.
   230                 HeapChunk::Destroy(chunk);
   231                 continue;
   232             }
   233             empty = chunk;                
   234         }
   235         prev = chunk->nextp();
   236     }
   237 
   238     if (empty) {
   239         *empty->nextp() = NULL;
   240         *last_->nextp() = empty;
   241     }
   242 }
   243 
   244 void
   245 OldSpace::resetFreeList()
   246 {
   247     freelist_.reset();
   248 }
   249 
   250 LargeObjectSpace::LargeObjectSpace()
   251   : first_(NULL),
   252     last_(NULL)
   253 {
   254 }
   255 
   256 LargeObjectSpace::~LargeObjectSpace()
   257 {
   258     while (first_) {
   259         HeapChunk *temp = first_->next();
   260         HeapChunk::Destroy(first_);
   261         first_ = temp;
   262     }
   263 }
   264 
   265 bool
   266 LargeObjectSpace::initialize()
   267 {
   268     return true;
   269 }
   270 
   271 Address
   272 LargeObjectSpace::allocate(size_t nbytes)
   273 {
   274     assert(IsAligned(nbytes, kObjectAlignment));
   275 
   276     // Always allocate a new chunk for large objects.
   277     HeapChunk *chunk = HeapChunk::New(last_, nbytes);
   278     if (!chunk)
   279         return NULL;
   280 
   281     if (!first_)
   282         first_ = chunk;
   283     last_ = chunk;
   284 
   285     return chunk->first();
   286 }
   287 
   288 void
   289 LargeObjectSpace::sweep()
   290 {
   291     if (!first_)
   292         return;
   293 
   294     HeapChunk **pprev = &first_;
   295     do {
   296         HeapChunk *chunk = *pprev;
   297         Object *obj = reinterpret_cast<Object *>(chunk->first());
   298         MarkBit bit = HeapChunk::GetMarkBit(obj);
   299         if (HeapChunk::IsWhite(bit)) {
   300             *pprev = chunk->next();
   301             HeapChunk::Destroy(chunk);
   302         } else {
   303             assert(HeapChunk::IsBlack(bit));
   304             HeapChunk::Clear(bit);
   305             pprev = chunk->nextp();
   306             last_ = chunk;
   307         }
   308     } while (*pprev);
   309 }