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