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