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