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