src/Zone.cpp
author David Anderson <dvander@alliedmods.net>
Sun Sep 16 21:59:26 2012 -0700 (2012-09-16)
changeset 190 dd04fce774cd
parent 188 bab29bcec7fe
child 195 c1ba166f3fc4
permissions -rw-r--r--
Enable dynamic array declarations.
dvander@45
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@45
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@0
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@69
    19
#include <stdlib.h>
dvander@0
    20
#include "Zone.h"
dvander@54
    21
#include "StringPool.h"
dvander@11
    22
#include "TypeManager.h"
dvander@61
    23
#include "GlobalRoots.h"
dvander@54
    24
#include "AllocatorPolicies.h"
dvander@65
    25
#include "Array.h"
danderson@92
    26
#include "Spaces-inl.h"
danderson@92
    27
#include "Heap-inl.h"
dvander@0
    28
dvander@59
    29
using namespace ke;
dvander@0
    30
dvander@60
    31
Zone *ke::SingleThreadedZone;
dvander@0
    32
dvander@11
    33
Zone::Zone()
dvander@69
    34
  : stack_(thisFromCtor()),
dvander@69
    35
    heap_(thisFromCtor()),
dvander@51
    36
    types_(NULL),
dvander@61
    37
    symbols_(NULL),
dvander@61
    38
    globalRoots_(NULL),
dvander@69
    39
    lastLocalRoot_(NULL),
dvander@69
    40
    hasPendingException_(false),
dvander@69
    41
    reporter_(NULL)
dvander@11
    42
{
dvander@11
    43
}
dvander@11
    44
dvander@54
    45
Zone::~Zone()
dvander@54
    46
{
dvander@61
    47
    delete types_;
dvander@54
    48
    delete symbols_;
dvander@61
    49
    delete globalRoots_;
dvander@54
    50
}
dvander@54
    51
dvander@0
    52
bool
dvander@0
    53
Zone::initialize()
dvander@0
    54
{
dvander@0
    55
    if (!stack_.initialize())
dvander@0
    56
        return false;
dvander@11
    57
    if (!heap_.initialize())
dvander@11
    58
        return false;
dvander@11
    59
dvander@54
    60
    symbols_ = new StringPool(this);
dvander@54
    61
    if (!symbols_ || !symbols_->initialize())
dvander@54
    62
        return false;
dvander@54
    63
dvander@61
    64
    globalRoots_ = new GlobalRoots(this);
dvander@61
    65
    if (!globalRoots_ || !globalRoots_->initialize())
dvander@61
    66
        return false;
dvander@61
    67
dvander@11
    68
    maps_[MapKind_Meta] = heap_.metaMap();
dvander@12
    69
    if ((maps_[MapKind_Type] = allocateMap(MapKind_Type, sizeof(Map))) == NULL)
dvander@12
    70
        return false;
dvander@12
    71
    if ((maps_[MapKind_FixedArray] = allocateMap(MapKind_FixedArray, sizeof(Map))) == NULL)
dvander@12
    72
        return false;
dvander@12
    73
    if ((maps_[MapKind_ByteArray] = allocateMap(MapKind_ByteArray, sizeof(Map))) == NULL)
dvander@12
    74
        return false;
dvander@12
    75
    if ((maps_[MapKind_Code] = allocateMap(MapKind_Code, sizeof(Map))) == NULL)
dvander@12
    76
        return false;
dvander@14
    77
    if ((maps_[MapKind_Reference] = allocateMap(MapKind_Reference, sizeof(Map))) == NULL)
dvander@14
    78
        return false;
dvander@12
    79
    if ((maps_[MapKind_MetaArray] = allocateMap(MapKind_MetaArray, sizeof(Map))) == NULL)
dvander@11
    80
        return false;
dvander@147
    81
    if ((maps_[MapKind_MetaStruct] = allocateMap(MapKind_MetaStruct, sizeof(Map))) == NULL)
dvander@147
    82
        return false;
dvander@85
    83
    if ((maps_[MapKind_MetaEnvironment] = allocateMap(MapKind_MetaEnvironment, sizeof(Map))) == NULL)
dvander@85
    84
        return false;
dvander@14
    85
    if ((maps_[MapKind_Module] = allocateMap(MapKind_Module, sizeof(Map))) == NULL)
dvander@14
    86
        return false;
dvander@26
    87
    if ((maps_[MapKind_Function] = allocateMap(MapKind_Function, sizeof(Map))) == NULL)
dvander@26
    88
        return false;
dvander@54
    89
    if ((maps_[MapKind_String] = allocateMap(MapKind_String, sizeof(Map))) == NULL)
dvander@54
    90
        return false;
dvander@68
    91
    if ((maps_[MapKind_Native] = allocateMap(MapKind_Native, sizeof(Map))) == NULL)
dvander@68
    92
        return false;
dvander@146
    93
    if ((maps_[MapKind_Descriptor] = allocateMap(MapKind_Descriptor, sizeof(Map))) == NULL)
dvander@146
    94
        return false;
dvander@168
    95
    if ((maps_[MapKind_Box] = allocateMap(MapKind_Box, sizeof(Map))) == NULL)
dvander@168
    96
        return false;
dvander@53
    97
    if ((maps_[MapKind_FreeRegion] = allocateMap(MapKind_FreeRegion, sizeof(Map))) == NULL)
dvander@53
    98
        return false;
dvander@85
    99
    if ((maps_[MapKind_EnvironmentSlotDescriptorArray] =
dvander@85
   100
         allocateMap(MapKind_EnvironmentSlotDescriptorArray, sizeof(Map))) == NULL)
dvander@85
   101
    {
dvander@85
   102
        return false;
dvander@85
   103
    }
dvander@11
   104
dvander@11
   105
    types_ = new TypeManager(this);
dvander@11
   106
    if (!types_ || !types_->initialize())
dvander@11
   107
        return false;
dvander@11
   108
dvander@65
   109
    // Create the cached array maps for generic arrays. This is for the API
dvander@65
   110
    // version of Invoke(), which needs to make arrays very quickly from C++.
dvander@65
   111
    {
dvander@65
   112
        // Generic "cell" array (contents do not matter, just non-gc things).
dvander@65
   113
        Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
dvander@65
   114
        if (!type)
dvander@65
   115
            return false;
dvander@65
   116
dvander@188
   117
        type = types_->newExternalArray(type);
dvander@65
   118
        if (!type)
dvander@65
   119
            return false;
dvander@65
   120
dvander@188
   121
        externalGenericArrayMap_ = ArrayMap::Attach(this, type);
dvander@188
   122
        if (!externalGenericArrayMap_)
dvander@65
   123
            return false;
dvander@65
   124
dvander@65
   125
        type = types_->getPrimitive(PrimitiveType_Char);
dvander@65
   126
        if (!type)
dvander@65
   127
            return false;
dvander@65
   128
dvander@188
   129
        type = types_->newExternalArray(type);
dvander@65
   130
        if (!type)
dvander@65
   131
            return false;
dvander@65
   132
dvander@188
   133
        externalCharArrayMap_ = ArrayMap::Attach(this, type);
dvander@188
   134
        if (!externalCharArrayMap_)
dvander@65
   135
            return false;
dvander@65
   136
    }
dvander@65
   137
dvander@0
   138
    return true;
dvander@0
   139
}
dvander@12
   140
dvander@12
   141
Map *
dvander@12
   142
Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
dvander@12
   143
{
dvander@12
   144
    assert(maps_[parent]);
dvander@12
   145
    Map *map = heap_.allocateMap(kind, bytes);
dvander@12
   146
    if (!map)
dvander@12
   147
        return NULL;
dvander@12
   148
    map->init(maps_[parent]);
dvander@12
   149
    return map;
dvander@12
   150
}
dvander@45
   151
dvander@45
   152
void
dvander@45
   153
Zone::accept(VirtualObjectVisitor *visitor)
dvander@45
   154
{
dvander@45
   155
    for (unsigned i = 0; i < MapKinds_Total; i++)
dvander@45
   156
        visitor->visit(maps_[i].address());
dvander@188
   157
    visitor->visit(externalCharArrayMap_.address());
dvander@188
   158
    visitor->visit(externalGenericArrayMap_.address());
dvander@45
   159
    types()->accept(visitor);
dvander@45
   160
dvander@45
   161
    Local<Object> *local = lastLocalRoot_;
dvander@45
   162
    while (local) {
dvander@45
   163
        visitor->visit(local->address());
dvander@45
   164
        local = local->prev();
dvander@45
   165
    }
dvander@45
   166
dvander@61
   167
    globalRoots_->accept(visitor);
dvander@45
   168
    rootScopes_.accept(visitor);
dvander@51
   169
dvander@51
   170
    stack_.accept(visitor);
dvander@45
   171
}
dvander@45
   172
dvander@54
   173
String *
dvander@54
   174
Zone::makeSymbol(const char *str, size_t length)
dvander@54
   175
{
dvander@54
   176
    return symbols_->add(str, length);
dvander@54
   177
}
dvander@54
   178
dvander@54
   179
String *
dvander@54
   180
Zone::makeSymbol(const char *str)
dvander@54
   181
{
dvander@54
   182
    return makeSymbol(str, strlen(str));
dvander@54
   183
}
dvander@54
   184
dvander@69
   185
bool
dvander@69
   186
Zone::hasPendingException()
dvander@69
   187
{
dvander@69
   188
    return hasPendingException_;
dvander@69
   189
}
dvander@69
   190
dvander@69
   191
void
dvander@69
   192
Zone::reportOutOfMemory()
dvander@69
   193
{
dvander@69
   194
    
dvander@69
   195
}
dvander@69
   196
dvander@69
   197
void
dvander@69
   198
Zone::reportError(Message message, ...)
dvander@69
   199
{
dvander@69
   200
    va_list ap;
dvander@69
   201
    va_start(ap, message);
dvander@69
   202
    reportErrorVA(message, ap);
dvander@69
   203
    va_end(ap);
dvander@69
   204
}
dvander@69
   205
dvander@69
   206
#if defined(_MSC_VER)
dvander@69
   207
# define VA_COPY(to, from)  to = from
dvander@69
   208
#else
dvander@69
   209
# define VA_COPY(to, from)  va_copy(to, from)
dvander@69
   210
#endif
dvander@69
   211
dvander@69
   212
static char *
dvander@69
   213
BuildErrorMessage(const char *format, va_list ap)
dvander@69
   214
{
dvander@69
   215
    va_list use;
dvander@69
   216
    VA_COPY(use, ap);
dvander@69
   217
dvander@69
   218
    // We over-allocate and zero terminate ahead of time, since LIBCRT's
dvander@69
   219
    // version of vsnprintf is screwy.
dvander@69
   220
    size_t size = 255;
dvander@69
   221
    char *buffer = (char *)calloc(size + 1, 1);
dvander@69
   222
    if (!buffer)
dvander@69
   223
        return NULL;
dvander@69
   224
dvander@69
   225
    for (;;) {
dvander@69
   226
        int r = vsnprintf(buffer, size, format, use);
dvander@69
   227
dvander@69
   228
        if (r > -1 && size_t(r) < size)
dvander@69
   229
            return buffer;
dvander@69
   230
       
dvander@69
   231
#if defined(_MSC_VER)
dvander@69
   232
        if (r < 0)
dvander@69
   233
            size *= 2;
dvander@69
   234
#else
dvander@69
   235
        if (r > -1)
dvander@69
   236
            size = size_t(r) + 1;
dvander@69
   237
        else
dvander@69
   238
            size *= 2;
dvander@69
   239
#endif
dvander@69
   240
dvander@69
   241
        free(buffer);
dvander@69
   242
        if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
dvander@69
   243
            return NULL;
dvander@69
   244
dvander@69
   245
        VA_COPY(use, ap);
dvander@69
   246
    }
dvander@69
   247
}
dvander@69
   248
dvander@69
   249
void
dvander@69
   250
Zone::reportErrorVA(Message message, va_list ap)
dvander@69
   251
{
dvander@69
   252
    char *report = BuildErrorMessage(Messages[message].format, ap);
dvander@69
   253
    if (!report) {
dvander@69
   254
        reportOutOfMemory();
dvander@69
   255
        return;
dvander@69
   256
    }
dvander@69
   257
dvander@69
   258
    if (reporter_) {
dvander@69
   259
        // Reporters can re-enter. When we start having actual exception
dvander@69
   260
        // objects that can be caught and inspected, this code will have to
dvander@69
   261
        // save and restore the exception state.
dvander@69
   262
        reporter_->onUncaughtException(report);
dvander@69
   263
    }
dvander@69
   264
dvander@69
   265
    hasPendingException_ = true;
dvander@69
   266
dvander@69
   267
    free(report);
dvander@69
   268
}
dvander@69
   269
dvander@69
   270
void
dvander@69
   271
Zone::beginCompilationErrors(const char *file)
dvander@69
   272
{
dvander@69
   273
    if (reporter_)
dvander@69
   274
        reporter_->beginCompilationErrors(file);
dvander@69
   275
}
dvander@69
   276
dvander@69
   277
void
dvander@69
   278
Zone::reportCompilationError(Message message, unsigned line, unsigned col, va_list ap)
dvander@69
   279
{
dvander@69
   280
    char *report = BuildErrorMessage(Messages[message].format, ap);
dvander@69
   281
    if (!report) {
dvander@69
   282
        reportOutOfMemory();
dvander@69
   283
        return;
dvander@69
   284
    }
dvander@69
   285
dvander@69
   286
    if (reporter_) {
dvander@69
   287
        // Reporters can re-enter. When we start having actual exception
dvander@69
   288
        // objects that can be caught and inspected, this code will have to
dvander@69
   289
        // save and restore the exception state.
dvander@69
   290
        reporter_->reportCompilationError(report, line, col);
dvander@69
   291
    }
dvander@69
   292
dvander@69
   293
    free(report);
dvander@69
   294
}
dvander@69
   295
dvander@69
   296
void
dvander@69
   297
Zone::endCompilationErrors()
dvander@69
   298
{
dvander@69
   299
    if (reporter_)
dvander@69
   300
        reporter_->endCompilationErrors();
dvander@69
   301
}
dvander@69
   302
dvander@69
   303
void
dvander@69
   304
Zone::installErrorReporter(Ke::IMessageReporter *reporter)
dvander@69
   305
{
dvander@69
   306
    reporter_ = reporter;
dvander@69
   307
}
dvander@69
   308
dvander@54
   309
void
dvander@54
   310
ZoneAllocatorPolicy::reportOutOfMemory()
dvander@54
   311
{
dvander@69
   312
    ZONE()->reportOutOfMemory();
dvander@54
   313
}
dvander@54
   314
dvander@54
   315
void
dvander@54
   316
ZoneAllocatorPolicy::reportAllocationOverflow()
dvander@54
   317
{
dvander@69
   318
    ZONE()->reportError(Message_AllocationOverflow);
dvander@54
   319
}
dvander@129
   320
dvander@129
   321
void
dvander@129
   322
Zone::clearPendingException()
dvander@129
   323
{
dvander@129
   324
    hasPendingException_ = false;
dvander@129
   325
}
dvander@129
   326