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